1. 线性表的顺序存储结构——顺序表
顺序表基本运算的实现:
1)建立顺序表
其方法是将给定的含有
n
个元素的数组的每个元素依次放入到顺序表中,并将
n
赋给顺序表的长度成员。算法如下:
void CreateList(SqList *&L,ElemType a[],int n)
//建立顺序表
{ int i;
L=(SqList *)malloc(sizeof(SqList));
for (i=0;i<n;i++)
L->data[i]=a[i];
L->length=n;
}
2)顺序表基本运算算法
(1)初始化线性表InitList(L)
该运算返回一个值表示
L
是否为空表。若
L
为空表,则返回
true
,否则返回
false
。
4)求线性表的长度ListLength(L)
该运算的结果是构造一个空的线性表
L
。实际上只需将
length
成员设置为
0
即可。
<strong> void InitList(SqList *&L) //引用型指针
{ L=(SqList *)malloc(sizeof(SqList));
//分配存放线性表的空间
L->length=0;
}</strong>
本算法的时间复杂度为
O(1)
。
(2)销毁线性表
该运算的结果是释放线性表
L
占用的内存空间。
<strong> void DestroyList(SqList *&L)
{
free(L);
}</strong>
本算法的时间复杂度为
O(1)
。
3)判定是否为空表ListEmpty(L)
<strong> bool ListEmpty(SqList *L)
{
return(L->length==0);
}</strong>
本算法的时间复杂度为
O(1)
。
4)求线性表的长度ListLength(L)
该运算返回顺序表
L
的长度。实际上只需返回
length
成员的值即可。
<strong>int ListLength(SqList *L)
{
return(L->length);
}</strong>
本算法的时间复杂度为
O(1)
。
5)输出线性表DispList(L)
![]()
该运算当线性表
L
不为空时
,
顺序显示
L
中各元素的值。
<strong> void DispList(SqList *L)
{ int i;
if (ListEmpty(L)) return;
for (i=0;i<L->length;i++)
printf("%c",L->data[i]);
printf("\n");
} </strong>
本算法中基本运算为
for
循环中的
printf
语句,故时间复杂度为
:
O(L
-
>length)
或
O(
n
)
6)求某个数据元素值GetElem(L,i,e)
该运算返回
L
中第
i
(
1
≤
i
≤
ListLength(L)
)个元素的值,存放在
e
中。
<strong>bool GetElem(SqList *L,int i,ElemType &e)
{ if (i<1 || i>L->length) return false;
e=L->data[i-1];
return true;
}</strong>
本算法的时间复杂度为
O(1)
。
7)按元素值查找LocateElem(L,e)
该运算顺序查找第
1
个值域与
e
相等的元素的逻辑位序。若这样的元素不存在,则返回值为
0
。
<strong> int LocateElem(SqList *L, ElemType e)
{ int i=0;
while (i<L->length && L->data[i]!=e) i++;
if (i>=L->length) return 0;
else return i+1;
}</strong>
本算法中基本运算为
while
循环中的
i++
语句,故时间复杂度为
:
O(L
->
length)
或
O(
n
)
8)插入数据元素ListInsert(L,i,e)
该运算在顺序表 L 的第 i ( 1 ≤ i ≤ ListLength(L)+1 )个位置上插入 新的元素 e 。如果 i 值不正确,则显示相应错误信息;否则将顺序表 原来第 i 个元素及以后元素均后移一个位置,移动方向从右向左, 如下图所示,腾出一个空位置插入新元素,最后顺序表长度增 1 。
该运算在顺序表 L 的第 i ( 1 ≤ i ≤ ListLength(L)+1 )个位置上插入 新的元素 e 。如果 i 值不正确,则显示相应错误信息;否则将顺序表 原来第 i 个元素及以后元素均后移一个位置,移动方向从右向左, 如下图所示,腾出一个空位置插入新元素,最后顺序表长度增 1 。
<strong>bool ListInsert(SqList *&L,int i,ElemType e)
{ int j;
if (i<1 || i>L->length+1)
return false; //参数错误时返回false
i--; //将顺序表逻辑序号转化为物理序号
for (j=L->length;j>i;j--) //将data[i..n]元素后移一个位置
L->data[j]=L->data[j-1];
L->data[i]=e; //插入元素e
L->length++; //顺序表长度增1
return true; //成功插入返回true
}</strong>
插入算法的平均时间复杂度为
O(
n
)
。
9)删除数据元素ListDelete(L,i,e)
该运算删除顺序表
L
的第
i
(
1
≤
i
≤
ListLength(L)
)个元素。如果
i
值不正确,则显示相应错误信息;否则将线性表第
i
个元素以后元素均向
前移动一个位置,移动方向为从左向右,如下图所示,这样覆盖了原来的第
i
个元素,达到删除该元素的目的,最后顺序表长度减
1
。
<strong> bool ListDelete(SqList *&L,int i,ElemType &e)
{ int j;
if (i<1 || i>L->length) //参数错误时返回false
return false;
i--; //将顺序表逻辑序号转化为物理序号
e=L->data[i];
for (j=i;j<L->length-1;j++) //将data[i..n-1]元素前移
L->data[j]=L->data[j+1];
L->length--; //顺序表长度减1
return true; //成功删除返回true
}</strong>
删除算法的平均时间复杂度为
O(
n
)
。
2.线性表基本运算在单链表上的实现
1)初始化线性表InitList(L)
<strong> void InitList(LinkList *&L)
{ L=(LinkList *)malloc(sizeof(LinkList));
//创建头节点
L->next=NULL;
}</strong>
本算法的时间复杂度为
O(1)
。
2)销毁线性表DestroyList(L)
本算法的时间复杂度为O(n)。
释放单链表
L
占用的内存空间。即逐一释放全部节点的空间。
<strong>void DestroyList(LinkList *&L)
{ LinkList *pre=L,*p=p->next; //pre指向*p的前驱节点
while (p!=NULL) //扫描单链表L
{ free(pre); //释放*pre节点
pre=p; //pre、p同步后移一个节点
p=pre->next;
}
free(pre); //循环结束时,p为NULL,pre指向尾节点,释放它
}</strong>
3)判线性表是否为空表ListEmpty(L)
若单链表
L
没有数据节点,则返回真,否则返回假。
<strong> bool ListEmpty(LinkList *L)
{
return(L->next==NULL);
}</strong>
本算法的时间复杂度为
O(1)
。
4)求线性表的长度ListLength(L)
返回单链表
L
中数据节点的个数。
<strong>int ListLength(LinkList *L)
{ int n=0;
LinkList *p=L; //p指向头节点,n置为0(即头节点的序号为0)
while (p->next!=NULL)
{ n++;
p=p->next;
}
return(n); //循环结束,p指向尾节点,其序号n为节点个数
}</strong>
本算法的时间复杂度为
O(n)
。
5)输出线性表DispList(L)
逐一扫描单链表
L
的每个数据节点,并显示各节点的
data
域值。
<strong>void DispList(LinkList *L)
{ LinkList *p=L->next; //p指向开始节点
while (p!=NULL) //p不为NULL,输出*p节点的data域
{ printf("%d ",p->data);
p=p->next; //p移向下一个节点
}
printf("\n");
}</strong>
本算法的时间复杂度为O(n)。
6)求线性表L中指定位置的某个数据元素GetElem(L,i,&e)
在单链表
L
中从头开始找到第
i
个节点,若存在第
i
个数据节点,则将其
data
域值赋给变量
e
。
<strong> bool GetElem(LinkList *L,int i,ElemType &e)
{ int j=0;
LinkList *p=L; //p指向头节点,j置为0(即头节点的序号为0)
while (j<i && p!=NULL) //找第i个节点
{ j++;
p=p->next;
}
if (p==NULL) //不存在第i个数据节点,返回false
return false;
else //存在第i个数据节点,返回true
{ e=p->data;
return true;
}
}</strong>
本算法的时间复杂度为O(n)。
7)按元素值查找LocateElem(L,e)
在单链表
L
中从头开始找第
1
个值域与
e
相等的节点,若存在这样的节点,则返回位置,否则返回
0
。
<strong>int LocateElem(LinkList *L,ElemType e)
{ int i=1;
LinkList *p=L->next; //p指向开始节点,i置为1
while (p!=NULL && p->data!=e)
{ p=p->next; //查找data值为e的节点,其序号为i
i++;
}
if (p==NULL) //不存在元素值为e的节点,返回0
return(0);
else //存在元素值为e的节点,返回其逻辑序号i
return(i);
}</strong>
本算法的时间复杂度为
O(n)
。
8)插入数据元素ListInsert(&L,i,e)
先在单链表
L
中找到第
i
-1
个节点
*p
,若存在这样的节点,将值为
e
的节点
*s
插入到其后。
<strong> bool ListInsert(LinkList *&L,int i,ElemType e)
{ int j=0;
LinkList *p=L,*s; //p指向头节点,j置为0
while (j<i-1 && p!=NULL) //查找第i-1个节点
{ j++;
p=p->next;
}
if (p==NULL) //未找到第i-1个节点,返回false
return false;
else //找到第i-1个节点*p,插入新节点并返回true
{ s=(LinkList *)malloc(sizeof(LinkList));
s->data=e; //创建新节点*s,其data域置为e
s->next=p->next; //将*s插入到*p之后
p->next=s;
return true;
}
}</strong>
本算法的时间复杂度为
O(n)
。
9)删除数据元素ListDelete(&L,i,&e)
先在单链表
L
中找到第
i
-1个节点*
p
,若存在这样的节点,且也存在后继节点,则删除该后继节点。
<strong> bool ListDelete(LinkList *&L,int i,ElemType &e)
{ int j=0;
LinkList *p=L,*q; //p指向头节点,j置为0
while (j<i-1 && p!=NULL) //查找第i-1个节点
{ j++;
p=p->next;
}
if (p==NULL) //未找到第i-1个节点,返回false
return false;
else //找到第i-1个节点*p
{ q=p->next; //q指向第i个节点
if (q==NULL) //若不存在第i个节点,返回false
return false;
e=q->data;
p->next=q->next; //从单链表中删除*q节点
free(q); //释放*q节点
return true; //返回true表示成功删除第i个节点
}
}</strong>
本算法的时间复杂度为
O(1)
。