详解顺序表

170 阅读7分钟

顺序表的定义及其特点;

顺序存储表示:用一组地址连续的存储单元依次存储线性表的数据元素的方式,具有顺序存储结构的特点(数据间的逻辑关系和物理关系是一致的)

假设线性表 L 存储的起始位置为 LOC(A) ,sizeof(ElemType) 是每个数据元素所占用存储空间的大小,则表 L 所对应的顺序存储如下图:

注意:线性表中的位序是从 1 开始的,而数组中元素的下标是从 0 开始的 

线性表的顺序存储结构是一种随机存取的存储结构,即通过首地址和元素序号可以在O(1) 时间内找到指定的元素

由于线性表的长度可变,且所需最大存储空间随问题的不同而不同,在C语言中通常使用动态分配的一维数组表示线性表

顺序表的运算

顺序表的主要运算包括:

初始化

创建一个空的顺序表,并指定其最大容量。

/*顺序表初始化*/
int init(SeqList *L)
{
	L->length = 0;
	return 0;
}

插入

在指定位置插入一个元素,需要将插入位置后的元素依次后移。

/*插入元素*/
int insert(SeqList *L, int i, DataType x)
{
	int j;

	/*判断是否满*/
	if(full(L))
	{
		printf("Error[10001],顺序表已满!\n");
		return 10001;
	}
	/*判断位置i合法性*/
	if(i<1 || i>length(L)+1)
	{
		printf("位置i不合法!\n");
		return 10002;
	}

	/*移动元素,向后移动*/
	for(j=L->length;j>=i;j--)
	{
		L->data[j] = L->data[j-1];
	}
	L->data[j] = x;
	L->length++;
	return 0; /*ok!*/
}

删除

删除指定位置的元素,需要将删除位置后的元素依次前移一个。


/*删除元素*/
int delete(SeqList *L, int i, DataType *x)
{
	/*判断位置i合法性*/
	if(i<1 || i>length(L)+1)
	{
		printf("Error[10002],位置i不合法!\n");
		return 10002;
	}
	int j; 
	// 从删除位置把数据往前移 第n-1个 
	for (j = i-1; j < L ->length; j++)
	{
		L->data[j] = L->data[j+1];
	}
	L->length--;
	return 0;
}

遍历

按顺序依次访问顺序表中的所有元素。

/*输出顺序表*/
void print(SeqList *L)
{
	int i;

	if(empty(L))
	{
		printf("顺序表为空!");
		return ;
	}
	printf("顺序表为:");
	for(i=0;i<L->length;i++)
	{
		printf(" %d ", L->data[i]);
	}
	printf("\n");
}

顺序表完成的起始都可以在突发时刻,即时间复杂度为O(1),因为元素在内存中是连续存储的。但是在插入和删除操作中,如果需要间隔地调整顺序表的结构,可能会导致数据迁移,造成一定的时间开销。

顺序表的实现(详细的介绍及C程序代码、执行结果)

完整代码

项目结构

手把手教你c语言如何引用自己的 .h 头文件

h 的方法似于 java 的接口方法

│  main.c
│  SeqList.c
│  SeqList.h
│  welcome.h

项目文件

C语言讲义——传值、传引用 - 虎老狮 - 博客园 (cnblogs.com)

暗号:看你说不说你的宿舍地址
地址==指针

SeqList.h

/*

	SeqList.h 顺序表定义
*/

#define MAXSIZE 1000
 
typedef int DataType;

/*顺序表*/
typedef struct
{
	DataType data[MAXSIZE];
	int length;
}SeqList;

/*顺序表初始化*/
int init(SeqList *L);

/*顺序表的长度*/
int length(SeqList *L);

/*顺序表是否满*/
int full(SeqList *L);

/*是否空*/
int empty(SeqList *L);

/*插入元素*/
int insert(SeqList *L, int i, DataType x);

/*删除元素*/
int delete(SeqList *L, int i, DataType *x);

/*输出顺序表*/
void print(SeqList *L);

SeqList.c

/*
	SeqList.c 顺序表实现
*/
#include "SeqList.h"


/*顺序表初始化*/
int init(SeqList *L)
{
	L->length = 0;
	return 0;
}


/*顺序表的长度*/
int length(SeqList *L)
{
	return L->length;
}

/*顺序表是否满*/
int full(SeqList *L)
{
	return (L->length == MAXSIZE)?1:0;
}

/*是否空*/
int empty(SeqList *L)
{
	return (L->length == 0)?1:0;
}

/*插入元素*/
int insert(SeqList *L, int i, DataType x)
{
	int j;

	/*判断是否满*/
	if(full(L))
	{
		printf("Error[10001],顺序表已满!\n");
		return 10001;
	}
	/*判断位置i合法性*/
	if(i<1 || i>length(L)+1)
	{
		printf("位置i不合法!\n");
		return 10002;
	}

	/*移动元素,向后移动*/
	for(j=L->length;j>=i;j--)
	{
		L->data[j] = L->data[j-1];
	}
	L->data[j] = x;
	L->length++;
	return 0; /*ok!*/
}


/*删除元素*/
int delete(SeqList *L, int i, DataType *x)
{
	/*判断位置i合法性*/
	if(i<1 || i>length(L)+1)
	{
		printf("Error[10002],位置i不合法!\n");
		return 10002;
	}
	int j; 
	for (j = i-1; j < L ->length; j++)
	{
		L->data[j] = L->data[j+1];
	}
	L->length--;
	return 0;
}

/*输出顺序表*/
void print(SeqList *L)
{
	int i;

	if(empty(L))
	{
		printf("顺序表为空!");
		return ;
	}
	printf("顺序表为:");
	for(i=0;i<L->length;i++)
	{
		printf(" %d ", L->data[i]);
	}
	printf("\n");
}

welcome.h

char welcome[] = "welcome";

main.c

#include <stdio.h>
#include "SeqList.h"
#include <string.h>
#include "welcome.h"

int main(int argc, char* argv[])
{
	SeqList L;
	int cmd;
	int i;
	int m,n;

	DataType x;
	
	for(i=0;i<strlen(welcome);i++)
	{
		printf("%c",welcome[i]);
		for(m=0;m<10000;m++)
			for(n=0;n<1000;n++)
			{
				;
			}
	}
	printf("\n\n\n");
	printf("-----------顺序表演示程序----------\n");
	do
	{
		printf("1. 初始化顺序表\n");
		printf("2. 插入元素\n");
		printf("3. 删除元素\n");
		printf("4. 判断顺序表是否为空\n");
		printf("5. 判断顺序表是否满\n");
		printf("6. 输出顺序表\n");
		printf("10. 帮助\n"); 
		printf("0. 退出\n");
		printf("请输入您要进行的操作(1~6,0退出):");
		scanf("%d", &cmd);
		switch(cmd)
		{
		case 1:
			if(!init(&L))
			{
				printf("顺序表已初始化!\n");
			}
			break;
		case 2:
			printf("请输入位置i,插入元素x(i,x):");
			scanf("%d,%d",&i,&x);
			if(!insert(&L,i,x))
			{
				printf("元素(%d)已插入位置[%d]\n",x, i);
			}
			break;
		case 3:
			printf("请输入位置i,删除元素x(i):");
			scanf("%d",&i);
			
			if(!delete(&L,i,x))
			{
				printf("元素(%d)删除位置[%d]\n",x, i);
			}
			break;
		case 4:
			if(!empty(&L))
			{
				printf("顺序表不为空!\n");
			}
			else
			{
				printf("顺序表为空!\n");
			}
			break;
		case 5:
			if(full(&L))
			{
				printf("顺序表已满!\n");
			}
			else
			{
				printf("顺序表未满!\n");
			}
			break;
		case 6:
			print(&L);
			break;
		case 10:
			printf(" 本程序为顺序表的演示程序,有XXX设计开发,程序完成了。。。。功能!。。。\n");
			break;
			
		}
	}while(cmd != 0);

	return 0;
}

运行结果

小结

顺序表是一种常见的线性表数据结构,它由一组连续的存储空间组成,可以通过下标直接访问元素。顺序表具有随机访问的特性,使得查找、插入和删除等操作具有较高的效率。 

顺序表的主要特点是元素在内存中的连续存储,这使得访问元素的时间复杂度为O(1),即常数时间。与链表相比,顺序表的随机访问效率更高。另外,顺序表还可以通过下标进行快速遍历,对于需要频繁访问和修改元素的场景,顺序表是一种很好的选择。 

在实际应用中,顺序表适用于元素数量固定、操作频繁的场景。例如,在某些算法中,需要对大量数据进行排序、查找等操作,此时使用顺序表能够更快地访问和处理数据。此外,顺序表还可以用于实现其他数据结构,如栈和队列等。 

然而,顺序表也存在一些限制。

  1. 首先,顺序表的容量是固定的,在初始化时需要指定最大容量,一旦超过容量限制就无法添加新元素。
  2. 其次,在插入和删除操作中,需要移动大量数据,可能会带来较大的时间开销。因此,在需要频繁插入和删除元素的场景下,可能不适合使用顺序表。

综上所述,顺序表是一种简单而高效的数据结构,适用于元素数量固定、频繁访问和修改的场景。根据实际需求,我们可以选择合适的数据结构来处理和操作数据,如b+树、跳表。。。以提高程序的效率和性能。

B+树看这一篇就够了(B+树查找、插入、删除全上) - 知乎 (zhihu.com)

一文搞懂跳表原理及实现 - 掘金 (juejin.cn)

参考文献

1. 数据结构C语言严蔚敏版(第二版)超详细笔记附带课后习题

2. ora.ai