数据结构第一章(线性表的顺序结构)
线性表是数据结构中最简单最基本的数据结构,其所表示的结构是线性结构,也是数据结构中最常用、最重要的形式之一。
顺序表
所谓顺序表就是用一组地址连续的储存单元按顺序存储线性表中的数据结构,这说明只要知道顺序表的首地址和每个数据元素所占存储单元的个数,就可求出任何一个元素的地址,而且求每个元素的所需的时间是相同的,这就使得顺序表具有按数据的序号进行随机存储的特点。
线性表的顺序存储结构类型定义如下:
(静态存储)
#define MaxSize 100 //线性表存储空间的最大增量
typedef struct{
ElemType data[MaxSize]; //存储空间基址,数组指针data指示线性表的基地址
int length; //线性表的当前长度
}SqList;
不过由于线性表的长度并不确定,所需要的最大存储空间因问题的不同而不同,而且有的时候很难估算,所以常常使用动态分配的指针方式来表示顺序存储结构。
动态顺序结构描述如下:
#define ListInitSize 100 //线性表的初始大小
#define ListIncrement 10 //线性表存储空间的分配增量
typedef struct{
ElemType *data; //存储空间基地址,由data表示
int length;
int MaxSize; //当前分配的存储最大容量
}SqList;
注意:
1.C语言中数组的下标是从0开始的,使用时注意下标范围;
2.是注意数据元素的下标访问方式和指针访问方式的区别。例如,若L是SqList类型的顺序表,则表中第i
个数据元素是L.data[i-1]或L.*(data+i-1)
下面是顺序表的一些基本操作
1.初始化顺序表
Status InitList_Sq(SqList &L) //构造一个空的链表
{
L.data = (ElemType*)malloc(ListInitSize *sizeof(ElemType)); //分配存储单元
if(!L.data)
return OVERFLOW //存储分配失败
L.length = 0; //线性表的长度为0
L.MaxSize = ListInitSize; //初始存储容量
return OK;
}
2.线性表清空
void ClearList(SqList &L) //清除线性表L中的所有元素,使之成为一个空表
{
if(L.data != NULL) //线性表非空,将长度置为0
L.length = 0;
}
3.查找定位
int SearchList(SqList L,ElemType X)
//在线性表中查找x相等的值,找到则返回该元素在表中的位置,否则返回-1
{
int i = 0;
while(i < L.Length && L.data[i]!=x)
i++; //找到位置
if(i < L.length)
return i+1; //成功找到
else
return -1; //没找到
}
4.遍历
void Traverse(SqList L)
{
int i = 0;
if(!L.data)
exit(0);
for(int i =0;i < L.length;i++)
printf("%d ",L.data[i]);
printf("\n");
}
5.插入元素
Status InsertList(SqList &L,int i,ElemType e)
{//在顺序线性表L中第i个位置之前插入新的元素e
if(i<1 || i>L.length+1) //检查i值的有效性,无效时直接返回
return -1;
if(L.length >= L.MaxSize){ //检查空间,如果当时存储空间已满,则增加分配
newbase = (ElemType *)realloc(L.data,(L.MaxSize+ListIncrement)*sizeof(ElemType));
if(!newbase) //储存空间失败
return -1;
L.data = newbase; //储存成功,赋新基址
L.MaxSize+=ListIncrement; //修改表的存储容量
}
for(int j = L.length-1;j >= i;j--)
L.data[j+1] = L.data[j]; //插入位置之后逐次向后移动(注意这里要从后往前循环)
L.data[i-1] = e; //插入e
++L.length; //表长加1
return 1;
}
6.删除元素
Status DeleteList(SqList &L,int i ,ElemType &e)
{//删除顺序线性表L中的第i个元素,如果该元素存在,用e返回其值
if(i < 1 || i > L.length) //检查i值的有效性,无效时直接返回
return 0;
e = L.data[i-1]; //将被删除元素的值赋给e
for(int j = 1;j <= L.length ; j++)
L.data[j-1] = L.data[j]; //被删除元素之后的元素逐个前移
--L.length;
return 1;
}
在上述实现的典型操作算法中,除查找、遍历、插入和删除外,算法的时间复杂度都是O(1)。
对于遍历算法,因为是把所有元素访问了一遍,所以对于有n个元素的线性表来说,执行次数为n,时间
复杂度为O(n)。
同样地,对于插入算法与删除算法的时间复杂度也为O(n)。