Logo

郎哥编程

理解顺序表:案例引导与实战演练

2026-07-21 93

图书馆的书目信息表就是一个线性表,表中的元素就是一条记录。记录由索引号、图书名称、作者、出版社等数据项构成。本文讨论了C语言和Pyhton语言如何定义一个顺序表,并实现了顺序表的插入、访问和删除运算。

采用顺序存储结构的线性表称为顺序表,顺序表就是在内存中开辟一段连续的存储空间,依次存储线性表中的数据元素。

一、定义顺序表

定义顺序表有两种方式:一种是静态地定义一张顺序表;一种是动态地生成一张顺序表。

下面是图书馆数目信息表:

表 1-3图书馆书目信息表

索引号 图书名称 作者 出版社
T218.717 Java编程 张甲 科技甲出版社
J035.890 Python编程 甲乙 科技乙出版社
K200.190 C语言编程 丙丁 科技丙出版社
…… …… …… ……

C语言可以定义一个结构体来存储书目信息:

typedef struct{
char strIndex[30]; // 索引号
char name[50];     // 图书名称
char author[15];   // 作者
char press[50];    // 出版社
}BOOKINFO;

Python语言可以定义一个类来存储书目信息

# 定义一个名为BookInfo的类
class BookInfo:
    def __init__(self, index,name,author,press):
        self.index = index  # 索引号
        self.name = name    # 图书名称
        self.author = author  # 作者
        self.press = press    # 出版社

书目信息结构已定义,下一步来定义顺序表,顺序表的元素为书目信息结构。在已知图书数量并且图书数量在一段时间基本不变的情况下,可以采用静态顺序表来存储书目信息。

定义静态顺序表C语言代码如下:

// 顺序表容量
#define MAX_BOOKSIZE  10000
// 定义一张静态顺序表
BOOKINFO  bookList[MAX_BOOKSIZE];

在C语言定义一张静态顺序表和定义数组的方法完全相同。

Python语言的列表是基于顺序表结构的对象,它本身就是动态顺序表,可以随时扩充顺序表的内存空间,用于存储更多的数据元素。下面重点讨论C语言动态顺序表的实现。

使用C语言动态生成一张顺序表,可以定义一个可动态扩展的数组,数组元素为BOOKINFO结构体。宏定义CAPACITY为动态数组的默认容量,pBookArray为指向动态数组的指针,nBookSize为动态数组当前长度,nCurrentCapacity为动态数组当前容量。

代码清单:

// 定义空指针
# define NULL 0
//线性表申请内存的默认容量 
#define CAPACITY      100
//指向线性表的指针,默认值为NULL
BOOKINFO *pBookArray = NULL;
//线性表当前长度,默认为0
int  nBookSize = 0;
// 线性表当前容量
int nCurrentCapacity = 0;

指向动态数组的指针pBookArray默认为空,程序运行后需要为数组申请内存,内存大小为CAPACITY*sizeof(BOOKINFO),并将申请的内存全部初始化为0。

代码清单:

// 初始化pBookArray,默认容量为CAPACITY
pBookArray = (BOOKINFO*)calloc(CAPACITY,sizeof(BOOKINFO));
memset(pBookArray,0,CAPACITY*sizeof(BOOKINFO));
if( NULL == pBookArray )
{
   printf("内存申请失败,程序将关闭");
   exit(-1);
}

现在我们已经通过上述代码生成了一张动态顺序表,顺序表可以存储的元素为BOOKINFO结构体。下面重点讨论顺序表的插入、访问和删除运算。

二、插入运算

INSERT(L,index,Element)

该运算在长度为n的L表中插入一个数据元素Element,插入前L表的长度为n,插入后L表的长度为n+1。index为插入元素的位置,index其后的元素都需要往后移动一个位置。若index为0,则需要移动n个元素;若index为1,仅需要移动一个元素。插入元素平均要移动的元素个数为(n-1)/2,因此顺序表插入运算的算法时间复杂度为O(n)。

C语言实现

/**
运算:在第index个元素和第index个元素之间插入一个元素
描述:该运算在长度为n的顺序表中插入一个数据元素,
      插入前顺序表的长度为n,插入后顺序表的长度为n+1。  
参数:pArray   顺序表地址
      index    元素插入的序号
	  bookInfo  
*/
int  InsertBookInfo(BOOKINFO* pArray,int index,BOOKINFO bookInfo)
{
	int i;
	char  *p1,*p2;
	if( index<0 )
		return -1;
	// 若元素已满,重新申请内容
	if( (nBookSize+1) > nCurrentCapacity )
	{
		nCurrentCapacity += CAPACITY;
	    pBookArray = (BOOKINFO*)realloc(pBookArray,sizeof(BOOKINFO)*nCurrentCapacity);
		if( NULL == pBookArray )
		{
			printf("内存申请失败,程序将关闭");
			exit(-1);
		}
	}
	for( i=(nBookSize>0?(nBookSize):0);i>index;i-- )
	{
		p1 = (char*)pArray;
		p1 += ((i)*sizeof(BOOKINFO));
		p2 = (char*)pArray;
		p2 += (i-1)*sizeof(BOOKINFO);
		memcpy(p1,p2,sizeof(BOOKINFO));
	}
	memcpy((char*)pArray+index*sizeof(BOOKINFO),&bookInfo,sizeof(BOOKINFO));
	nBookSize += 1;
}

InsertBookInfo函数首先判断顺序表存储空间是否已满,若已满则扩展存储空间,然后将index及其后的所有元素都顺序移动到下一个位置,最后将bookInfo指向的内存区域拷贝到顺序表索引为index的位置。

三、访问运算

GET(L,index)

该运算从L表中得到第index个数据元素,index为顺序表的序号。因为顺序表采用顺序存储结构,可以直接通过index来定位元素,因此查询元素的时间复杂度为O(1)。

C语言实现

/**
运算:访问第index个数据元素
描述:该运算从顺序表中得到第index个数据元素,
      index为顺序表的序号。
参数:pArray   顺序表
      index    访问的元素序号
*/
BOOKINFO* GetBookInfo(BOOKINFO* pArray,int index)
{
	char* p = (char*)pArray;
	// 若线性表长度为0,返回NULL值
	if( nBookSize <=0  )
		return NULL;
	// 若index小于0或大于等于线性表长度,返回NULL值
	if( index<0 || index >= nBookSize )
		return NULL;
	// 返回线性表的第1个元素
	if( index == 0 )
		return pArray;
	// 返回线性表的第index个元素
	return (BOOKINFO*)(p+index*sizeof(BOOKINFO));
}

GetBookInfo函数将线性表指针pArray赋值给字符指针变量p,参数index为访问元素的索引,即访问元素在线性表内的序号,字符指针p加上index个BOOKINFO的字节数即为访问元素的指针,返回时将指针强制转换为BOOKINFO指针。

四、删除运算

DELETE(L,index)

该运算从L表中删除第index个数据元素,该运算并不是真正删除第index个数据元素,而是将index其后的所有元素都顺序往前移动一个位置,覆盖掉index位置的元素。因此删除元素的时间复杂度为O(n)。

C语言实现

/**
运算:删除index位置的元素
描述:该运算在长度为n的顺序表中删除一个数据元素,
      删除前顺序表的长度为n,删除后顺序表的长度为n-1。  
参数:pArray   顺序表
      index    待删除元素的序号
	  bookInfo  
*/
int  DeleteBookInfo(BOOKINFO* pArray,int index)
{
	int i;
	char  *p1,*p2;
	if( index<0 )
		return -1;
	if( index >= nBookSize )
		return -1;
	// 删除最后一个元素
	if( index == nBookSize - 1  )
	{
		// 顺序表长度减1即可
		nBookSize = nBookSize - 1;
		return 0;
	}
	// index其后的所有元素都顺序往前移动一个位置
	for( i=index+1; i < (nBookSize>0?(nBookSize):0);i++ )
	{
		p1 = (char*)pArray;
		p1 += ((i)*sizeof(BOOKINFO));
		p2 = (char*)pArray;
		p2 += (i-1)*sizeof(BOOKINFO);
		memcpy(p2,p1,sizeof(BOOKINFO));
	}
	nBookSize -= 1;
}

DeleteBookInfo函数首先判断index的合法性,若index不合法,函数返回-1。若是删除最后一个元素,无需移动顺序表的元素,将顺序表长度减1即可,否则需要将index其后的所有元素都顺序往前移动一个位置。

 

评论区

登录 后发表评论
暂无评论