线性表
线性表
什么是线性表
“线性表(Linear List)”:由同类型数据元素构成有序序列的线性结构
- 表中元素个数称为线性表的长度
- 线性表没有元素时,称为空表
- 表起始位置称表头,表结束位置称表尾
线性表的抽象数据类型描述
类型名称:线性表
数据对象集:线性表是\(n(\ge0)\)个元素构成的有序序列\((a_1,a_2,\cdots,a_n)\)
操作集:线性表\(L\in List\),整数\(i\)表示位置,元素\(X\in ElementType\),线性表基本操作主要有:
- List MakeEmpty():初始化一个空线性表\(L\);
- ElementType FindKth(int K, List L):根据位序\(K\),返回相应的元素;
- int Find(ElementType X, List L):在线性表\(L\)中查找\(X\)的第一次出现位置;
- void Insert(ElementType X, int i, List L):在位序\(i\)前插入一个新元素\(X\);
- void Delete(int i, List L):删除指定位序\(i\)的元素;
- int Length(List i):返回线性表\(L\)的长度\(n\)
线性表的顺序存储实现
利用数组的连续存储空间存放线性表的各元素
typedef struct LNode *List;
struct LNode{
ElementType Data[MAXSIZE];
int Last;
};
struct LNode L;
List Ptrl;
访问下标为\(i\)的元素:\(L.Data[i]\)或\(Ptrl->Data[i]\)
线性表的长度:\(L.Last+1\)或\(PtrL->Last+1\)
主要操作的实现
初始化(建立空的顺序表)
List MakeEmpty(){
List PtrL;
PtrL=(List)malloc(sizeof(struct LNode));//通过malloc申请这样一个结构
PtrL->Last=-1;//把结构的Last设为-1,Last=0表示有一个元素放在第一个位置,空表Last设为-1
return PtrL;//最后返回这个结构的指针
}
查找
int Find(ElementType X, List PtrL){
int i=0;
while(i <= PrtL->Last && PrtL->Data[i] != X)
i++;//查找成功的平均比较次数为(n+1)/2,平均时间性能为O(n)
if (i > Ptrl->Last)
return -1;//如果没找到,返回-1
else
return i; //找到后返回的是存储位置
}
插入
在第\(i\)(\(1\le i\le n+1\))个位置上插入一个值为\(X\)的新元素
1就插在线性表的头上;\(n+1\)是插在线性表的最后
线性表是在数组里表示的,下标是从0开始的
实际上要把元素放到i-1的位置
首先,要把i-1之后的这些元素全部往后挪一位,先移动,再插入
从后面开始挪,把第n个元素挪到第n+1个元素上
void Insert(ElementType X, int i, List PrtL){
int j;
if (PtrL->Last == MAXSIZE-1){//表空间已满,不能插入
printf(" 表满 ");
return;
}
if (i < 1 || i>PtrL->Last+1){// 检查插入位置的合法性
printf(" 位置不合法 ");
return;
}
for (j = PtrL->Last; j >= i-1; j--)
PrtL->Data[j+1] = PtrL->Data[j]; //将ai~an倒序向后移动
PtrL->Data[i-1]=X; //新元素插入
PtrL->Last++; //Last仍指向最后元素
return;
}
删除
删除表的第\(i\)(\(1\le i\le n\)$)个位置上的元素
数组对应的下标就是0到n-1
将第\(i\)个元素移掉,第\(i\)个元素的位置空出来了,所以必须把\(i\)之后的这些元素全部往前挪
要删掉的是第\(i\)个位置上的元素,也就是下标为\(i-1\)的元素
所以这个时候要把它后面的那个元素挪到前面来
下标为\(i\)的元素挪到\(i-1\),下标为\(i+1\)的元素挪到\(i\)
按照从左往右的顺序往前挪
void Delete(int i, List PtrL){
int j;
if (i < 1 || i > PtrL->Last+1){ //检查空表及删除位置的合法性
printf("不存在第%d个元素", i);
return;
}
for (j = i; j <= PtrL->Last; j++)
PtrL->Data[j-1]=PtrL->Data[j];//将a_{i+1}~a_n向前移动
PtrL->Last--; //Last仍指向最后元素
return;
}
//平均挪动次数为(0+n-1)/2,平均时间性能为O(n)
线性表的链式存储实现
不要求逻辑上相邻的两个元素物理上也相邻;通过”链“建立起数据元素之间的逻辑关系
插入、删除不需要移动数据元素,只需要修改”链“
typedef struct LNode *List;
struct LNode{
ElementType Data;
List Next;
};
struct LNode L;
List PtrL;
主要操作的实现
求表长
int Length(List PtrL){
List p = PtrL; //p指向表的第一个结点
int j=0;
while (p){
p=p->Next;
j++;//当前p指向的是第j个结点
}
return j;
}
//时间性能为O(n)
查找
- 按序号查找:FindKth
List FindKth(int K, List PtrL){
List p = PtrL;
int i = 1;
while (p != NULL && i < K){ //一个表不空,一个i小于K
p=p->Next;
i++;
}
if (i == K)
return p; //找到第L个返回指针
else
return NULL; //否则返回空
}//平均时间性能为O(n)
- 按值查找:Find
List Find(ElementType X, List PtrL){
List p = PtrL;
while (p != NULL && p->Data != X) //一个表不空,一个没找到X
p=p->Next;
return p; // 一个可能是找到了,返回X所在节点的地址;一个可能是没找到,返回NULL
}//平均时间性能为O(n)
插入
在第\(i-1\,(1\le i\le n+1)\)个结点侯插入一个值为\(X\)的新节点
(1)先构造一个新节点,用\(s\)指向;(用malloc函数来申请一块空间)
(2)再找到链表的第\(i-1\)个结点,用\(p\)指向;
(3)然后修改指针,插入结点(\(p\)之后插入新节点是\(s\))
List Insert(ElementType X, int i, List PtrL){
List p, s;
if (i == 1){ //新结点插入在表头
s=(List)malloc(sizeof(struct LNode)); //申请、装填结点
s->Data=X;
s->Next=PtrL;
return s; // 返回新表头指针
}
p = FindKth(i-1, PtrL); //查找第i-1个结点
if (p == NULL){ //第i-1个不存在,不能插入
printf(" 参数i错");
return NULL;
}
else{
s = (List)malloc(sizeof(struct LNode));//申请、装填结点
s->Data = X;
s->Next = p->Next;//新节点插入在第i-1个结点的后面
p->Next = s;
return PtrL;
}
}
删除
删除链表第\(i\,(1\le i\le n)\)个位置上的结点
(1)先找到链表的第\(i-1\)个结点,用\(p\)指向;
(2)再用指针\(s\)指向要被删除的结点(\(p\)的下一个结点);
(3)然后修改指针,删除\(s\)所指的结点
(4)最后释放\(s\)所指结点的空间
List Delete(int i, List PtrL){
List p, s;
if (i == 1){ //若要删除的是表的第一个结点
s = PtrL;//s指向第一个节点
if (PtrL != NULL) //如果第一个结点的指针不是空,则删除第一个结点
PtrL=PtrL->Next;
else
return NULL;
free(s); //释放被删除的结点的内存空间
return PtrL;
}
p = FindKth(i-1, PtrL); //查找第i-1个结点,返回第i-1个结点的指针
if (p == NULL){ //如果第i-1个结点的指针为空
printf("第%d个结点不存在", i-1);
return NULL;
}
else if (p->Next == NULL){
printf("第%d个结点不存在", i);
return NULL;
}
else{
s = p->Next; //s指向第i个结点
p->Next=s->Next;//从链表中删除第i个结点
free(s);//释放被删除结点的内存空间
return PtrL;
}
}