线性表的基本运算在单链表上的实现:
- 初始化 空表由一个头指针和一个头结点组成
LinkList InitiateLinkList()
//建立一个空的单链表
{
LinkList head; //头指针
head=malloc(sizeof(Node));//动态构建-结点,它是头结点
head->next=NULL;
return head
}
在算法中,变量head是链表的头指针,它指向创建的节点,即头结点.一个空链表禁有一个头结点,它的指针域为NULL.
2.求表长
在单链表储存结构中,线性表的表长等于单量表等于单链表中元素的节点个数,即除了头结点外的结点的个数.
设置一个工作指针p,初始时,p指向头结点,并设置一个计数器cnt,初值设置为0.然后,让工作指针p通过指针域逐个结点向尾结点移动,工作指针每向尾部移动一个结点,让计数器加1,直到工作指正p->next=null时,说明已经走到表的尾部,这时已完成对所有结点的访问,计数器cut的值即是表的长度.
3.读表元素
通常给定一个序号i,查找线性表的第i个元素.在链表中,任何相邻的两个节点通过一个指针相连,一个结点的位置包含在直接前驱结点的next域中,所以,必须从头指针出发,一直往后移动,直到第i个结点.
4.定位
线性表的定位运算,就是给定表元素的值,找出这个元素的位置.在单链表的实现中,则是给定一个结点的值,找出这个结点是单链表的第几个结点.定位运算又称作按值查找.在定位运算中,也需要重头到尾访问链表,直至找到需要的节点,返回其序号.若未找到,返回0.
int locateLinklist(LinkList head,DataType x)
{
Node*p=head; //p是工作指针
p=p->next; //初始时 p指向首结点
int i=0; //i代表结点的序号,这里置初始值为0;
while(p!=NULL&&p->data!=x)//访问链表
{
i++;
p=p->next;
}
if(p!=NULL) return i+1;
else return 0
}
5.插入:单链表的插入运算是将给定值为x的元素插入到链表head的第i个结点之前.
a. 先找到单链表的的第i-1个结点q.
b.生成一个值为x的新结点p,p的指针域指向q的直接后继结点,如下图
c.q的指针域指向p
void inserLinklist (LinkList head,DataType x,int i)
// 在表head的第i个元素结点之前插入一个以x为值得新节点
{
Node *p,*q;
if(i==1) q=head;
else q=GetLinklist(head,i-1);
if(q==NULL)
exit("找不到插入的位置");
else {
p=molloc(sizeof(Node));p->data=x; //生成新节点
p->next=q->next; //新结点链域指向*q的后继结点
q->next=p; //修改*q的链域
}
}
注意:链接操作 p->next=q->next和q->next=p两条语句的执行顺序不能颠倒,否则结点*q的链域值(即指向原链表第i个结点的指针)将丢失.
6.删除:删除运算是给定一个值i,将链表中第i个结点从链表中移出,并修改相关结点的指针域,以维持剩余结点的链接关系,将ai结点移出后,需要修改该结点的直接前驱结点的指针域,使其指向移出结点的ai的直接后继结点.
void deleteLinklist(LinkList head,int i)
//删除表head 的第i个结点
{
Node *q;
if(i==1) q=head;
else q=GetLinklist(head,i-1); //先找待删除结点的直接前驱
if(q!=NUll&&q->next!-NULL)
{
p=q->next;//p指向待删除结点
q->next=p->next; //移出待删结点
free(p); //释放已移出的结点p的空间
}
else exit("找不到要删除的节点"); //节点不存在
}
注意:free§是必不可少的,因为当一个结点从链表移出后,如果不释放它的空间,它将变成一个无用的结点,它会一直占用着系统内存空间,其他程序将无法使用这块空间.
7.双向循环链表:在单链表中的每个结点再设置一个指向其前驱的结点的指针域prior,这样每个结点有两个指针,其结构如图:
prior | data | next |
---|
prior与next类型相同,它指向直接前驱结点.头结点的prior指向最后一个结点,最后一个结点的next指向头结点,由这种结点构成的链表称为双向循环链表,
设置p指向待删结点,删除p可通过下述语句完成:
1)p->prior->next=p->next; //p钱驱结点的后链指向p的后继结点
2)p->next->prior=p->prior; //p后继结点的前链指向p的前驱结点
3)free§; // 释放p的空间
注意:(1) (1)的顺序可以颠倒
8.插入 在p所指向的结点的后面插入一个新结点*t,需要修改4个指针:
1)t-prior=p;
2)t->next=p->next;
3)p->next->prior=t;
4)p->next=t;
9.线性表和链表的时间性能和空间性能进行比较
- 对于按位置查找顺序表是随机存取,时间复杂度为O(1).单链表需要对表元素进行扫描,它时间复杂度为O(n).
2)对于定位运算,基于操作是比较,顺序表和单链表上的实现算法的的时间复杂度是相同的O(n)
3)对于插入,删除运算,在顺序表中,平均时间复杂度为O(n).在单链表中,其平均时间复杂度仍然为O(n)
10.线性表和链表的优缺点
1)单链表的每个结点包括数据域与指针域,指针需要占用额外的空间.
2)从整体考虑,顺序表要分配存储空间,如果预分配得过大,将造成浪费,若分配过小,又将发生上溢;单链表不需要预分配空间,只要空间内存没有耗尽,单链表中的结点个数就没有限制.