线性表是由同类型数据元素构成有序序列的线性结构,表中元素个数称为线性表的长度,线性表没有元素的时候称为空表,表起始位置称表头,结束位置称表尾。
线性表有数据对象集和操作集
数据对象集:线性表是n个元素构成的有序序列
操作集:线性表L属于List,整数i表示位置,元素X属于ElementType
线性表基本操作主要有
List MakeEmpty(): 初始化一个空线性表
ElementType FindKth(int K,List L): 在线性表L中查找第K个元素
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 L):返回线性表L的长度n
同一个问题可以有不同的表现(存储)方法
线性表的顺序存储实现:利用数组的连续存储空间顺序存放线性表的各元素
typedef struct{
ElementType Data[MAXSIZE]; //定义一个数组,类型为ElementType:想为什么类型都可以
int Last; //代表线性表的最后一个元素
}List;
List L, *PtrL;
访问下标为i的元素:L.Data[i]或PtrL->Data[i]
线性表的长度:L.Last+1或PtrL->Last+1
主要操作的实现
- 初始化(建立空的顺序表)
List *MakeEmpty(){
List *PtrL;
PtrL = (List)malloc(sizeof(List)); //通过malloc函数为表申请内存空间
PtrL->Last = -1; //最后一个元素为-1,指该顺序表为空
return PtrL; //返回值真
}
- 查找
int Find(ElementType X, List *PtrL){
int i = 0;
while(i<=PtrL->Last && PtrL->Data[i] != X){
i++;
}
if(i > PtrL->Last) return -1; //如果没找到,返回-1
else return i; //找到后返回的是存储位置
}
- 插入操作实现
/*
从最后一个元素开始向后移动一个位置,移动了i个元素之后,将要插入的元素插入空缺的位置
若是从第i-1个元素开始向后移动,从Data[i-1]到Data[PtrL->Last+1]都是同一个值,值为移动之前的Data[i-1]
*/
void Insert(ElementType X,int i,List *PtrL){
int j;
if(PtrL->Last == MAXSIZE-1){ //判断表空间是否已满,已满则不能插入
printf("表满");
return;
}
if(i<1||i>PtrL->Last+2){
printf("位置不合法");
return;
}
for(j=PtrL->Last;j>=i-1;j--){
PtrL->Data[j+1] = PtrL(L->Data[j]); //将ai~an倒序向后移动
}
PtrL->Data[i-1] = X; //插入新元素
Ptrl->Last++; //Last仍指向最后元素
return;
}
- 删除操作实现
/*
删除操作和插入操作相反,插入操作是从最后一个元素往后移动直到第i-1个元素
删除操作是从第i+1个元素开始往前移动直到最后一个元素
*/
void Delete(int i, List *PtrL){
int j;
if(i<1||i>PtrL->Last+1){ //检查空表及删除位置的合法性
printf("不存在第%d个元素",i);
return;
}
for(j=i;i<=PtrL->Last;j++){
PtrL->Data[j-1] = PtrL->Data[j]; //将ai+1~an的顺序向前移动
}
PtrL->Last--; //Last仍然指向最后一个元素
}
线性表的链式存储实现
链表不要求逻辑上相邻的两个元素物理上也相邻,通过”链“建立起数据元素之间的逻辑关系。链表的插入、删除都不需要移动数据元素,只需要修改链。
typedef struct{
ElementType Data; //每个结点对应的数据
struct Node *Next; //代表下一个结点的位置
}List;
List L,*PtrL;
主要操作的实现
- 求表长
int Length(List *PtrL){
List *p = PtrL; //p指向表的第一个结点
int j=0;
while(p){
p=p->Next;
j++; //当前p指向的是第j个结点
}
return j;
}
- 查找(1.按序号查找)
List *FindKth(int K,List *PtrL){
List *p = PtrL;
int i = 1;
while(p!=NULL && i<K){
p=p->Next;
i++;
}
if(i==K) return p; //找到第K个,返回指针
else return NULL; //否则返回空
}
- 查找(2.按值查找)
List *Find(ElementType X,List *PtrL){
List *p = PtrL;
while(p!=NULL && p->Data != X){
p = p->Next;
}
return p;
}
- 插入
/*
在第i-1个(1<=i<=n+1)个结点后插入一个值为X的新结点
1.先构造一个新结点,用s指向
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(List)) //申请、填装结点
s->Data = X;
s->Next = Ptrl;
return s; //返回新表头指针
}
p = FindKth(i-1,PtrL); //查找第i-1个结点
if(p==NULL){
printf("参数i错误");
return NULL;
}else{
s = (List *)malloc(sizeof(List)); //申请、填装结点
s->Data = X;
//下面两条语句不能够改变顺序,不然值会有错误
s->Next = p->Next; //新结点插入在第i-1个结点的后面
p->Next = s;
return PtrL;
}
}
- 删除
/*
删除链表的第i(1<=i<=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个结点
if(p==NULL){
printf("第%d个结点不存在", i-1);
return NULL;
}else if(p->Next == NULL){
printf("第%d个结点不存在", i-1);
return NULL;
}else{
s = p->Next; //s指向第i个结点
p->Next = s->Next; //从链表中删除
free(s); //释放被删除结点
return PtrL;
}
}