线性表(Linear List):1.元素个数称为表长 2.表中没有元素称为空表 3.起始称表头,结束称表尾
线性表主要的基本操作:
1
、
List MakeEmpty()
:
初始化一个空线性表
L
;
2
、
ElementType FindKth( int K, List L )
:根据位序
K
,返回相应元素 ;
3
、
int Find( ElementType X, List L )
:在线性表
L
中查找
X
的第一次出现位置;
4
、
void Insert( ElementType X, int i, List L)
:在位序
i
前插入一个新元素
X
;
5
、
void Delete( int i, List L )
:删除指定位序
i
的元素;
6
、
int Length( List L )
:返回线性表
L
的长度
n
。
一、顺序存储实现
利用数组的连续存储空间顺序存放线性表的各元素。
(图源mooc陈越老师数据结构课件)
主要操作的实现:
1.初始化(建立空的顺序表)
List MakeEmpty()
{
List PtrL;
PtrL = (List)malloc(sizeof(struct LNode));
PtrL->Last = -1;
return PtrL;
}
2.查找
int Find(ElementType X, List PtrL)
{
int i=0;
while(i<=PtrL->Last && PtrL->Data[i]!=X)
{
i++;
}
if(i>PtrL->Last) return -1;
else return i;
}
3.插入
(图源mooc陈越老师数据结构课件)
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; i<=i; j--)
{
PtrL->Data[j+1] = PtrL->Data[j]; //将ai~an倒序向后移动一位
}
PtrL->Data[i-1] = X; //新元素插入
PtrL->Last++; //Last仍指向最后一个元素
return;
}
4.删除
(图源mooc陈越老师数据结构课件)
void Delete(List PtrL, int i)
{
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];
}
PtrL->Last--;
return;
}
二、链式存储实现
不要求逻辑上相邻的两个元素物理上也相邻。通过“链”建立起数据元素之间的逻辑关系。
插入、删除不需要移动数据元素,只需要修改“链”。
(图源mooc陈越老师数据结构课件)
主要操作的实现:
1.求表长
int Length(List PtrL)
{
List p = PtrL; //p指向表的第一个结点
int j=0;
while(p)
{
p = p->Next; //当前p指向的是第j个结点
j++;
}
return j;
}
2.查找,分两种。
//2.查找--按序号查找
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;
}
else return NULL;
}
//2’.查找--按值查找
List Find(ElementType X, List PtrL)
{
List p = PtrL;
while(p!=NULL && p->Data!=X)
{
p = p->Next;
}
return p;
}
3.插入
(1)先构造一个新结点,用s指向
(2)再找到链表的第i-1个结点,用p指向
(3)然后修改指针,插入结点
(图源mooc陈越老师数据结构课件)
注意:顺序不可更改!
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;
p->Next = s;
return PtrL;
}
}
4.删除
(1)先找到链表的第i-1个结点,用p指向
(2)再用指针s指向要被删除的结点(p的下一个结点)
(3)然后修改指针,删除s所指结点
(4)释放s所指结点的空间
(图源mooc陈越老师数据结构课件)
List Delete(int i,List PtrL)
{
List p,s;
if(i==1)
{
s = PtrL;
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); return NULL;
}else
{
s = p->Next; //s指向第i个结点
p->Next = s->Next;
free(s);
return PtrL;
}
}
三、二者比较
1.顺序存储:逻辑与物理统一;要求内存中可用存储单元的地址必须是连续的
优:易于查找和修改。
缺:不利于插入、删除操作。存储空间利用率低,可能造成空间浪费。
适宜做查找等的静态操作
若线性表的长度变化不大,且其主要操作是查找,则采用顺序表。
2.链式存储:相邻数据元素可随意存放(即逻辑与物理不必统一)
优:易于插入和删除,存储空间利用率高。
缺:不利于查找和修改,需要遍历整个链表。
适宜做插入、删除等的动态操作
若线性表的长度变化较大,且其主要操作是插入、删除,则采用链表。
(图源网络)