版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
数据结构李云清杨庆红揭安全人民邮电出版社高等学校精品课程(省级)国家十二五规划教材高等学校精品课程(省级)国家十二五规划教材第3章线性表及其链式存储揭安全jieanquan@163.com江西师范大学计算机信息工程学院第3章线性表的链式存储链式存储单链表带头结点的单链表循环单链表双链表链式栈链式队列
线性表的存储方式除了常用的顺序存储外,采用链式方式存储也是一种常见的方式。本章将介绍一般线性表的几种链式存储实现方式,如单链表、带头结点单链表、循环单链表、双链表以及特殊的线性表------栈和队列的链式存储实现。3.1链式存储
数据结构的存储方式必须体现它的逻辑关系。在链式存储方式下,实现中除存放一个结点的信息外,还需附设指针,用指针体现结点之间的逻辑关系。如果一个结点有多个后继或多个前驱,那么可以附设相应个数的指针,一个结点附设的指针指向的是这个结点的某个前驱或后继。
线性结构中,每个结点最多只有一个前驱和一个后继,这里暂且设定更关心它的后继,这样在存储时除了存放该结点的信息外,只要附设一个指针即可,该指针指向它的后继结点的存放位置。每个结点的存储形式是:infonext例,数据的逻辑结构B=(K,R)其中K={k1,k2,k3,k4,k5}R={r}R={<k1,k2>,<k2,k3>,<k3,k4>,<k4,k5>}是一个线性结构,它的链式存储如图所示100010011002100310041005100610071008存储地址infonextk41006k21007k11003k5∧k31005
为了清晰,上图可以更简洁地用下图表示。k1k5∧k2k3k4head3.2单链表
单链表是线性表链式存储的一种形式,其中的结点一般含有两个域,一个是存放数据信息的info域,另一个是指向该结点的后继结点的存放地址的指针域next。一个单链表必须有一个首指针指向单链表中的第一个结点。数据1指针◎数据2指针◎数据3指针◎数据域指针域…节点直观化的描述方法:单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名。例如:若头指针名是head,则把链表称为表head。head(a)非空表head=NULL(b)空表3.2.2单链表的实现
单链表结构的C语言描述如下:///
链表实现的头文件,文件名linklist.h
///typedefintdatatype;typedefstructlink_node{datatypeinfo;structlink_nodenext;}node;typedefnode*linklist;单链表几个基本操作的具体实现:建立一个空的单链表///
函数功能:建立一个空的单链表 //
函数参数:无 //
函数返回值:指向node类型变量的指针 //
文件名:slnklist.c,函数名:init() ///nodeinit()/建立一个空的单链表/
{
returnNULL;
}算法3.1建立一个空的单链表输出单链表中各个结点的值
voiddisplay(nodehead){nodep;p=head;if(!p)printf("\n单链表是空的!");
else
{
printf("\n单链表各个结点的值为:\n");
while(p){printf("%5d",p->info);p=p->next;}
}
}
算法3.2输出单链表中各个结点的值在单链表中查找第i个结点
nodefind(nodehead,inti){intj=1;nodep=head;if(i<1)returnNULL;while(p&&i!=j){p=p->next;j++;}returnp;}算法3.3在单链表中查找第i个结点单链表的插入过程见下图所示:
∧headpx(2)head=p;(1)(1)p->next=head;(a)在单链表的最前面插入一个值为x的新结点单链表的插入过程见下图所示:
∧head
(2)px(2)head=p;(a)在单链表的最前面插入一个值为x的新结点(1)(1)p->next=head;单链表的插入过程见下图所示:∧head
(b)在q所指的结点后插入一个p所指的值为x的新结点(1)p->next=q->next;xpq(1)单链表的插入过程见下图所示:∧head
x(b)在q所指的结点后插入一个p所指的值为x的新结点(1)p->next=q->next;pq(2)q->next=p;(1)(2)///
函数功能:单链表第i个结点后插入值为x的新结点
//
函数参数:指向node类型变量的指针head
//datatype类型变量x,int型变量I //
函数返回值:指向node类型变量的指针
//
文件名:slnklist.c,函数名:insert()
///nodeinsert(nodehead,datatypex,inti){nodep,q;
q=find(head,i); /查找第i个结点/
if(!q&&i!=0)
printf("\n找不到第%d个结点,不能插入%d!",i,x);
else{
p=(node)malloc(sizeof(node)); /分配空间/
p->info=x; /设置新结点/if(i==0){ /*插入的结点作为单链表的第一个结点*/
p->next=head; /插入(1)/head=p; /插入(2)/
}
else{p->next=q->next; /插入(1)/q->next=p; /插入(2)/}}
returnhead;}算法3.4在单链表中第i个结点后插入一个值为x的新结点1、申请空间s=malloc(...)2、填入数据域值s->info=ch;单链表应用-----建立单链表方法一:堆栈方式建立单链表(头插法)数据1^head数据2s数据33、新结点链入表头s->next=head;4、修改表头指针head=s;数据1^head数据2s数据34、修改表头指针head=s;单链表应用-----建立单链表方法一:堆栈方式建立单链表(头插法)#include“linklist.h”node*creatlistf(){datatypedata;node*head,*s;head=NULL;printf("\n\nPleaseinputthedataoflinklist\n");
scanf("%d",&data);while(data!=0){s=(node*)malloc(sizeof(node));s->info=data;s->next=head;head=s;
scanf("%d",&data);}returnhead;}1、申请空间s=malloc()2、填入数据域值s->info=ch;3、新结点链入表尾r->next=s;4、修改表尾指针r=s;方法二:队列方式建立单链表(尾插法)数据2head数据1s数据3r方法二:队列方式建立单链表(尾插法)数据2head数据1s数据3r关键一步:
设置一个链尾指针r,每次将新的结点链在r的后面,使其成为新的表尾结点。node*creatlistr(void){datatypedata;node*head,*s,*r;head=NULL;r=NULL;scanf("%d",&data);while(data){s=(node*)malloc(sizeof(node));s->info=data;/*产生新结点*/
if(head==NULL)head=s;/*新结点插入空表*/
elser->next=s;
r=s;scanf("%d",&data);
}/*处理表尾结点指针域*/以0作为输入结束条件if(r!=NULL)r->next=NULL;returnhead;}删除操作见下图所示:
∧headp(1)head=head->next;(a)删除单链表的最前面的(第一个)结点(2)free(p)删除操作见下图所示:
∧head(1)head=head->next;(a)删除单链表的最前面的(第一个)结点(2)free(p)(b)删除p指向的结点,pre为p的前驱结点(1)pre->next=p->next;∧head
prep(b)删除p指向的结点,pre为p的前驱结点(1)pre->next=p->next;∧head
prep(1)(b)删除p指向的结点,pre为p的前驱结点(1)
pre->next=p->next;∧head
pre(1)(2)free(p)///
函数功能:在单链表中删除一个值为x的结点 //
函数参数:指向node类型变量的指针head //datatype类型变量x //
函数返回值:指向node类型变量的指针 //
文件名:slnklist.c,函数名:dele() ///nodedele(nodehead,datatypex){nodepre=NULL,p;if(!head){printf("单链表是空的!");returnhead;}
p=head;
while(p&&p->info!=x) /没有找到并且没有找完/
{pre=p;p=p->next;} /pre指向p的前驱结点/
if(!pre&&p->info==x) /要删除的是第一个结点/
head=head->next; /删除(1)/elsepre->next=p->next;free(p);returnhead;}算法3.5在单链表中删除一个值为x的结点链式存储的插入和删除操作比顺序存储方便,但不能随机访问某个结点!3.3带头结点单链表
3.3.1带头结点单链表
带头结点单链表见下图所示:数据2数据1数据3headhead(A)空表(B)非空表^^3.3.2带头结点单链表的实现
一般的单链表中,第一个结点由head指示,而在带头结点单链表中,head指示的是所谓的头结点,它不是存储数据结构中的实际结点,第一个实际的结点是head->next指示的。在带头结点单链表的操作实现时要注意这一点。
nodeinit(){nodehead;head=(node)malloc(sizeof(node));head->next=NULL;returnhead;}算法3.6建立一个空的带头结点的单链表
请修改头插法与尾插法建表程序,以建立带头结点的单链表。
voiddisplay(nodehead){nodep;p=head->next; /从第一个(实际)结点开始/
if(!p)printf("\n带头结点的单链表是空的!");
else
{
printf("\n带头结点的单链表各个结点的值为:\n");
while(p){printf("%5d",p->info);p=p->next;}
}
}算法3.7输出带头结点的单链表中各个结点的值///
函数功能:在带头结点的单链表中查找第i个结点地址 //
函数参数:指向node类型变量的指针head //int类型变量i //
函数返回值:指向node类型变量的指针head //
文件名hlnklist.c,函数名find() ///nodefind(nodehead,inti){intj=0;nodep=head;if(i<0){printf("\n带头结点的单链表中不存在第%d个结点!",i);returnNULL;}
elseif(i==0)returnp; /*此时p指向的是头结点*/
while(p&&i!=j) /没有查找完并且还没有找到/
{
p=p->next;j++; /继续向后(左)查找,计数器加1/}returnp; /返回结果,i=0时,p指示的是头结点/
}算法3.8在带头结点的单链表中查找第i个结点带头结点单链表的插入过程见图3.7:∧x
(2)(1)(2)×qp(b)在q所指的结点后插入一个p所指的值为x的新结点(1)p->next=q->next;(2)q->next=p;headp
(2)
∧head×
(2)(1)x(1)p->next=q->next;(2)q->next=p;(a)非空带头结点单链表的最前面插入一个值为x的新结点q
带头结点的单链表的插入操作的具体实现见算法3.9。
///
函数功能:在带头结点的单链表中第i个结点后插入一个值为x的新结点
//
函数参数:指向node类型变量的指针head //datatype类型变量x,int型变量i //
函数返回值:指向node类型变量的指针head//
文件名:hlnklist.c,函数名:insert() ///nodeinsert(nodehead,datatypex,inti){nodep,q;q=find(head,i); /查找带头结点的单链表中的第i个结点/
/i=0,表示新结点插入在头结点之后,此时q指向的是头结点/
if(!q) /没有找到/
{printf("\n带头结点的单链表中不存在第%d个结点!不能插入%d!",i,x);returnhead;}
p=(node)malloc(sizeof(node)); /为准备插入的新结点分配空间/
p->info=x; /为新结点设置值x/p->next=q->next; /插入(1)/q->next=p; /插入(2),当i=0时,由于q指向的是头结点,本语句等价于head>next=p/returnhead;}算法3.9在带头结点的单链表中第i个结点后插入一个值为x的新结点带头结点单链表的删除过程见图3.8。
∧
head×q(1)head->next=q->next;(a)删除带头结点单链表的最前面的(第一个)实际结点
(1)(1)
(1)×(1)(b)在带头结点单链表中删除q指向的结点,pre为q的前驱结点(1)pre->next=q->next;preq∧head
nodedele(nodehead,datatypex){nodepre=head,q; /首先pre指向头结点/
q=head->next; /q从带头结点的第一个实际结点开始找值为x的结点/
while(q&&q->info!=x) /没有查找完并且还没有找到/
{pre=q;q=q->next;} /继续查找,pre指向q的前驱/
if(q){pre->next=q->next; /删除/
free(q); } /释放空间/
returnhead;
}算法3.10在带头结点的单链表中删除一个值为x的结点算法设计题:1、用单链表作为存储结构,实现线性表(a0,a1,…,an-1)就地逆置的操作,所谓就地指辅助空间应为O(1)。2、设单链表L是一个递减有序表,试写一算法将X插入其中后仍保持L的有序性。3、写一算法将单链表中值重复的结点删除,使所得的结果表中各结点值均不相同。4、设计一个算法,对单链表按结点值从小到大对结点进行排序。算法设计题:5、设计一个算法,将两个有序单链表合并成一个有序的单链表。6、设计一个算法,求两个单链表表示的集合的交集,并将结果用一个新的单链表保存并返回。
50
40
80
10^phead链表插入排序演示
50
40
80
10^phead^s^
50
40
80
10^phead^s^preq=head->next
while(q&&q->data<s->data){}pre=q;q=q->next;循环结束时,将s结点加在pre与q所指示的结点之间!
50
40
80
10^phead^s^preq=head->next
while(q&&q->data<s->data){}pre=q;q=q->next;s->next=q;pre->next=s;
50
40
80
10^pheads^preq=head->next
while(q&&q->data<s->data){}pre=q;q=q->next;s->next=q;pre->next=s;
50
40
80
10^pheads^preq=head->next
while(q&&q->data<s->data){}pre=q;q=q->next;s->next=q;pre->next=s;算法设计题:多相式相加问题:A(x)=7+3x+9x8+5x17B(x)=8x+22x7-9x8∧A703198517∧B81227-98C70111227∧5173.4循环单链表
3.4.1循环单链表head
循环单链表类型的描述(略)3.4.2循环单链表的实现
单链表中某个结点p是表中最后一个结点的特征是p->next==NULL。对于一个循环单链表,若首指针为head,表中的某个结点p是最后一个结点的特征应该是p->next==head。
循环单链表的头文件和单链表的相同。建立一个空的循环单链表
///
函数功能:建立一个空的循环单链表 //
函数参数:无 //
函数返回值:指向node类型变量的指针 //
文件名:clnklist.c,函数名init() ///nodeinit() /建立一个空的循环单链表/
{
returnNULL;
}算法3.11建立一个空的循环单链表
///
函数功能:获得循环单链表的最后一个结点的存储地址 //
函数参数:指向node类型变量的指针变量head //
函数返回值:指向node类型变量的指针 //
文件名:clnklist.c,函数名:rear() ///noderear(nodehead){nodep;if(!head) /循环单链表为空/
p=NULL;
else
{
p=head; /从第一个结点开始/
while(p->next!=head) /没有到达最后一个结点/
p=p->next; /继续向后/
}returnp;}算法3.12获得循环单链表的最后一个结点的存储地址///
函数功能:输出循环单链表中各个结点的值 //
函数参数:指向node类型变量的指针变量head //
函数返回值:空 //
文件名:clnklist.c,函数名:display() ///voiddisplay(nodehead){nodep;if(!head)printf("\n循环单链表是空的!\n");
else
{
printf("\n循环单链表各个结点的值分别为:\n");
printf("%5d",head->info);/输出非空表中第一个结点的值/
p=head->next; /p指向第一个结点的下一个结点/
while(p!=head) /没有回到第一个结点/
{
printf("%5d",p->info);
p=p->next;
}
}
}算法3.13输出循环单链表中各个结点的值///
函数功能:循环单链表中查找值为x的结点的存储地址//
函数参数:指向node类型变量的指针变量head
//datatype类型的变量x
//
函数返回值:指向node类型变量的指针
//
文件名:clnklist.c,函数名:find()
///nodefind(nodehead,datatypex){/查找一个值为x的结点/
nodeq;if(!head) /循环单链表是空的/
{
printf("\n循环单链表是空的!无法找指定结点!");
returnNULL;
}q=head; /q指向循环单链表的第一个结点,准备查找/
while(q->next!=head&&q->info!=x) /没有查找到并且没有查找完整个表/
q=q->next; /继续查找/
if(q->info==x)returnq;
else
returnNULL;
}算法3.14在循环单链表中查找一个值为x的结点循环单链表的插入过程如图:
headpx
rear(a)在循环单链表的最前面插入一个值为x的新结点(1)p->next=head;(2)head=p;(3)rear->next=p;循环单链表的插入过程如图:head
xqp(b)循环单链表,在q所指的结点后插入一个p所指的值为x的新结点(1)p->next=q->next;(2)q->next=p;///
函数功能:循环单链表第i个结点后插入值为x的新结点
//
函数参数:指向node类型变量的指针变量head
//datatype类型的变量x,int类型的变量I
//
函数返回值:指向node类型变量的指针 //
文件名:clnklist.c,函数名:insert()
///nodeinsert(nodehead,datatypex,inti){/*i为0时表示将值为x的结点插入作为循环单链表的第一个结点*/
nodep,q,*myrear;intj;p=(node)malloc(sizeof(node)); /分配空间/
p->info=x; /设置新结点的值/
if(i<0) /如果i小于0,则输出出错信息/
{printf("\n无法找到指定的插入位置!");free(p);returnhead;}if(i==0&&!head) /插入前循环单链表如果是空的,则新结点的指针域应指向它自己/
{p->next=p;head=p;returnhead;}
if(i==0&&head) /*在非空的循环单链表最前面插入*/
{myrear=rear(head); /找到循环单链表的最后一个结点/
p->next=head; /插入(1)/head=p;/插入(2)/myrear->next=p; /插入(3)最后一个结点的指针域指向新插入的表中第一个结点/
returnhead;}
if(i>0&&!head){printf("\n无法找到指定的插入位置!");free(p);returnhead;}
if(i>0&&head){ /*在非空的循环单链表中插入值为x的结点,并且插入的结点不是第一个结点*/
q=head; /准备从表中第一个结点开始查找/
j=1; /计数开始/
while(i!=j&&q->next!=head) /没有找到并且没有找遍整个表/
{
q=q->next;j++; /继续查找,计数器加1/}if(i!=j) /
找不到指定插入位置,即i的值超过表中结点的个数,则不进行插入/
{
printf("\n表中不存在第%d个结点,无法进行插入!\n",i);
free(p);
returnhead;
}
else
else{ /找到了第i个结点,插入x/p->next=q->next; /插入,修改指针(1)/q->next=p; /插入,修改指针(2)/returnhead;}}}算法3.15在循环单链表中第i个结点后插入一个值为x的新结点循环单链表的删除过程如图:
head×q(1)head=head->next;(2)pre->next=head;(a)删除循环单链表的最前面的(第一个)结点
(1)(1)pre
(2)×(2)循环单链表的删除过程如图:
(1)×(1)(b)删除q指向的结点,pre为q的前驱结点(q指向的不是循环单链表的第一个结点)(1)pre->next=q->next;preqhead
///
函数功能:在循环单链表中删除一个值为x的结点 /
/
函数参数:指向node类型变量的指针变量head //datatype类型的变量x //
函数返回值:指向node类型变量的指针 //
文件名:clnklist.c,函数名:dele() ///nodedele(nodehead,datatypex){nodepre=NULL,q; /q用于查找值为x的结点,pre指向q的前驱结点/
if(!head) /表为空,则无法做删除操作/
{
printf("\n循环单链表为空,无法做删除操作!");
returnhead;
}
q=head; /从第1个结点开始准备查找/
while(q->next!=head&&q->info!=x) /没有找遍整个表并且没有找到/
{
pre=q;
q=q->next; /pre为q的前驱,继续查找/
} /循环结束后,pre为q的前驱/
if(q->info!=x) /没找到/
{
printf("没有找到值为%d的结点!",x);
}
else /找到了,下面要删除q/{if(q!=head){pre->next=q->next;free(q);}else
if(head->next==head){free(q);head=NULL;}else{pre=head->next;while(pre->next!=q)pre=pre->next; /*找q的前驱结点位置*/
head=head->next;
pre->next=head;
free(q);
}
}
returnhead;
}算法3.16在循环单链表中删除一个值为x的结点3.循环单链表的整体插入与删除操作图3.12一个循环单链表整体插入到一个单链表前部的图示3.5双链表
3.5.1双链表
前面的各种链式表中,一个结点的指针域是指向它的后继结点的,如果需要找一个结点p的前驱结点,则必须从表首指针开始查找,当某个结点pre的指针域指向的是结点p时,即pre->next==p时,则说明pre是p的前驱结点。如果常常需要知道一个结点的前驱和后继结点,上述的链式表是不适合的。既然单链表中每个结点有一个指针域指向它的后继结点,那自然地想到再增设一个指针域指向它的前驱结点,这就构成了双链表。
双链表的结点包括三个域,一个是存放数据信息的info域,另外两个是指针域,这里用llink和rlink表示,llink指向它的前驱结点,rlink指向它的后继结点。双链表的一般情形如图所示:双链表类型的描述(略!)∧∧head3.5.2双链表的实现
双链表结构的C语言描述如下:///
双链表的头文件,文件名dlnklist.h
///typedefintdatatype;typedefstructdlink_node{datatypeinfo;structdlink_nodellink,rlink;}dnode;///
函数功能:输出双链表中各个结点的值 //
函数参数:指向dnode类型变量的指针head //
函数返回值:空 //
文件名:dlnklist.c,函数名:display() ///voiddisplay(dnodehead){dnodep;printf("\n");p=head;if(!p)printf("\n双链表是空的!\n");
else
{printf("\n双链表中各个结点的值为:\n");
while(p){printf("%5d",p->info);p=p->rlink;}
}
}算法3.18输出双链表中各个结点的值dnodefind(dnodehead,inti){intj=1;dnodep=head;if(i<1){printf("\n第%d个结点不存在!\n",i);returnNULL;}
while(p&&i!=j) /没有找完整个表并且没有找到/
{
p=p->rlink;j++;/继续沿着右指针向后查找,计数器加1/}if(!p){printf("\n第%d个结点不存在!\n",i);returnNULL;}
returnp;
}算法3.19查找双链表中第i个结点双链表插入过程如下图所示:x∧head(1)p->rlink=head;p(a)在双链表的最前面插入一个值为x的新结点(2)p->llink=NULL;(3)head->llink=p; (4)head=p;∧∧双链表插入过程如下图所示:
∧head
(1)p->rlink=q->rlink;∧qxp(b)在双链表中q所指结点的后面插入一个值为x的新结点(2)p->llink=q;(3)q->rlink->llink=p;(4)q->rlink=p;双链表插入过程如下图所示:
(1)p->rlink=q->rlink;qxp(c)在双链表中q所指结点(是最后一个结点)的后面插入一个值为x的新结点head
∧(2)p->llink=q;(3)q->rlink=p;∧∧///
函数功能:双链表第i个结点后插入值为x的新结点 //
函数参数:指向dnode类型变量的指针head //datatype类型的变量x,int类型的变量 //
函数返回值:指向dnode类型变量的指针 //
文件名:dlnklist.c,函数名:insert() ///dnode*insert(dnode*head,datatypex,inti){dnode*p,*q;p=(dnode*)malloc(sizeof(dnode)); /*分配空间*/
p->info=x; /*设置新结点的值*/
if(i==0) /*在最前面插入一个值为x的新结点*/
{
p->llink=NULL; /*新插入的结点没有前驱*/
p->rlink=head; /*新插入的结点的后继是原来双链表中的第一个结点*/
if(!head) /*原表为空*/
{
head=p;
}
else
{
head->llink=p; /*原来双链表中第一个结点的前驱是新插入的结点*/
head=p; /*新结点成为双链表的第一个结点*/
}
returnhead;
}
q=find(head,i); /*查找第i个结点*/
if(!q) /*第i个结点不存在*/
{printf("第%d个结点不存在,无法进行插入",i);free(p);returnhead;}
if(q->rlink==NULL) /*在最后一个结点后插入*/
{
p->rlink=q->rlink; /*即为NULL,新插入的结点没有后继。插入操作(1)*/
p->llink=q; /*插入操作(2)*/
q->rlink=p; /*插入操(4)*/
} /*注意不能和下面的一般情况一样处理,这里如执行下面的(3)将出错!*/
else /*一般情况下的插入*/
{
p->rlink=q->rlink; /*插入操作(1)*/
p->llink=q; /*插入操作(2)*/
q->rlink->llink=p; /*插入操作(3)*/
q->rlink=p; /*插入操作(4)*/
}
returnhead;
}算法3.20在双链表中第i个结点后插入一个值为x的新结点双链表删除操作图示:∧∧head(a)被删除的q是双链表中唯一的一个结点qNULL∧∧(b)被删除的q是双链表中的第一个结点(表中不只这一个结点)qhead(1)head=head->rlink;(2)head->llink=NULL;(1)
×∧(2)双链表删除操作图示:∧∧∧head(c)被删除的q是双链表中的最后一个结点qq->llink->rlink=NULL;∧∧q(1)q->llink->rlink=q->rlink;(2)q->rlink->llink=q->llink;(1)(2)head(d)被删除的q是双链表中既非第一也非最后的一个结点///
函数功能:在双链表中删除一个值为x的结点 //
函数参数:指向dnode类型变量的指针head //datatype类型的变量x //
函数返回值:指向dnode类型变量的指针 //
文件名:dlnklist.c,函数名:dele() ///dnodedele(dnodehead,datatypex){dnodeq;if(!head) /双链表为空,无法进行删除操作/
{printf("双链表为空,无法进行删除操作");returnhead;}
q=head;
while(q&&q->info!=x)q=q->rlink; /循环结束后q指向的是值为x的结点/
if(!q){printf("\n没有找到值为%d的结点!不做删除操作!",x);
}
if(q==head&&head->rlink) /被删除的结点是第一个结点并且表中不只一个结点/
{
head=head->rlink;
head->llink=NULL;
free(q);returnhead;
}
if(q==head&&!head->rlink)/被删除的结点是第一个结点并且表中只有这一个结点/
{
free(q);
returnNULL;/双链表置空/
}
else
{
if(!q->rlink)/被删除的结点是双链表中的最后一个结点/
{
q->llink->rlink=NULL;
free(q);
returnhead;
}
else
/q是有2个以上结点的双链表中的一个非开始、也非终端结点/
{
q->llink->rlink=q->rlink;
q->rlink->llink=q->llink;
free(q);returnhead;}}}算法3.21在双链表中删除一个值为x的结点3.6链式栈
3.6.1链式栈
栈的链式存储称为链式栈。链式栈就是一个特殊的单链表,对于这特殊的单链表,它的插入和删除规定在单链表的同一端进行。链式栈的栈顶指针一般用top表示,链式栈如下图所示。∧top3.6.2链式栈的实现
///
函数功能:读链式栈的栈顶结点值 //
函数参数:指向node类型变量的指针top //
函数返回值:datatype类型的变量 //
文件名:lnkstack.c,函数名:read() ///datatyperead(nodetop){if(!top){printf("\n链式栈是空的!");exit(1);}
return(top->info);} /*本函数可以调用empty()函数*/
算法3.24取得链式栈的栈顶结点值///
函数功能:输出链式栈中各个结点的值 //
函数参数:指向node类型变量的指针top //
函数返回值:空 //
文件名:lnkstack.c,函数名:display() ///voiddisplay(nodetop){nodep;
p=top;printf("\n");if(!p)printf("\n链式栈是空的!");
while(p){printf("%5d",p->info);p=p->next;}}算法3.25输出链式栈中各个结点的值∧xtopp(1)p->next=top;
链式栈插入操作链式栈进栈操作(1)∧xtopp
(2)(1)p->next=top;
链式栈插入操作(2)top=p;链式栈进栈操作向链式栈中插入一个值为x的结点
nodepush(nodetop,datatypex){nodep;p=(node)malloc(sizeof(node)); /分配空间/
p->info=x; /设置新结点的值/
p->next=top; /插入(1)/
top=p;
/插入(2)/
returntop;
}算法3.26向链式栈中插入一个值为x的结点∧top(1)q=top;
链式栈删除操作q链式栈出栈操作(2)top=top->next;(3)free(q)删除链式栈的栈顶结点
nodepop(nodetop){nodeq;if(!top){printf("\n链式栈是空的!");returnNULL;}
q=top; /指向被删除的结点(1)/
top=top->next; /删除栈顶结点(2)/
free(q);
returntop;
}算法3.27删除链式栈的栈顶结点3.7链式队列
3.7.1链式队列
队列的链式存储称为链式队列。链式队列就是一个特殊的单链表,对于这种特殊的单链表,它的插入和删除规定在单链表的不同端进行。链式队列的队首和队尾指针分别用front和rear表示,链式队列如下图所示。∧∧qufrontrear(a)空的链式队列∧qufrontrear(b)非空的链式队列3.7.2链式队列的实现
链式队列的结点定义和单链表一样。队列必须有队首和队尾指针,因此增加定义一个结构类型,其中的两个域分别为队首和队尾指针。其定义如下:typedefstruct{nodefront,rear;/定义队首与队尾指针/
}queue;建立一个空的链式队列
queueinit()/建立一个空的链式队列/
{
queuequ;qu=(queue)malloc(sizeof(queue)); /分配空间/
qu->front=NULL; /队首指针设置为空/
qu->rear=NULL; /队尾指针设置为空/
returnqu;
}算法3.28建立一个空的链式队列取得链式队列的队首结点值
///
函数功能:取得链式队列的队首结点值 //
函数参数:queue类型的变量qu //
函数返回值:datatype类型 //
文件名:lnkqueue.c,函数名:read() ///datatyperead(queuequ){if(!qu.front){printf("\n链式队列是空的!");exit(1);}
return(qu.front->info);
}算法3.31取得链式队列的队首结点值链式队列的插入过程图示见下图:x∧pqufrontrearqu->front=qu->rear=p;(a)向空链式队列中插入值为x的新结点链式队列的插入过程图示见下图:x∧p(1)qu->rear->next=p;(b)在非空链式队列中插入值为x的新结点qufrontrear(2)qu->rear=p;∧向链式队列中插入一个值为x的结点
queueinsert(queuequ,datatypex){nodep;p=(node)malloc(sizeof(node)); /分配空间/
p->info=x; /设置新结点的值/
p->next=NULL;
if(qu->front==NULL) /当前队列为空,新插入的结点为队列中惟一一个结点/
qu->front=qu->rear=p;
else
{
qu->rear->next=p; /队尾插入/
qu->rear=p;
}
returnqu;
}算法3.32向链式队列中插入一个值为x的结点链式队列的删除过程图示见下图:∧qqufrontrear(1)q=qu->front;(2)qu->front=q->next;(3)qu->rear=NULL;(a)链式队列删除操作(队列中只有一个结点)链式队列的删除过程图示见下图:
∧qufrontrear(b)链式队列删除操作(队列中不只一个结点)q(1)q=qu->front;(2)qu->front=q->next;删除链式队列中队首结点
queuedele(queuequ) /删除队首结点/
{
nodeq;if(!qu->front){printf("队列为空,无法删除!");returnqu;}
q=qu->front; /q指向队首结点(1)/
qu->front=q->next; /队首指针指向下一个结点(2)/
free(q); /释放原队首结点空间/
if(qu->front==NULL)qu->rear=NULL;/队列中的惟一结点被删除后,队列变空(3)/
returnqu;
}算法3.33删除链式队列中的队首结点3.1选择题(1)两个有序线性表分别具有n个元素与m个元素且n≤m,现将其归并成一个有序表,其最少的比较次数是()。A.n B.m C.n
−
1 D.m
+
n(2)非空的循环单链表head的尾结点(由p所指向)满足()。A.p->next==NULL
B.p==NULL C.p->next==head D.p==headAC(3)在带头结点的单链表中查找
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年度不锈钢栏杆生产设备采购与技术升级合同
- 滑动门用非金属滑轨市场发展预测和趋势分析
- 纸制宠物拾便袋市场发展现状调查及供需格局分析预测报告
- 运载工具用电压调节器市场发展现状调查及供需格局分析预测报告
- 2024年度云计算服务合同数据处理规定
- 2024年度广告代理合同协议
- 2024年度中秋月饼定制采购合同
- 游泳池用充气玩具市场需求与消费特点分析
- 皮制行李标签市场需求与消费特点分析
- 2024年度劳动合同(含薪资待遇、工作时间及福利制度)
- 2024年家庭教育新趋势:安全教育家长会
- 第十二届广东省安全知识竞赛暨粤港澳安全知识竞赛决赛备赛试题库(含答案)
- 完整2024年国有企业管理人员处分条例专题课件
- 安全生产治本攻坚三年行动实施方案(2024-2026年) - 副本
- GB/T 97.2-2002平垫圈倒角型A级
- 新教材人教A版高中数学选择性必修第二册全册教学课件(共541张)
- 六年级上册数学课件-6.1 分数混合运算 |西师大版 (共15张PPT)
- 中国话-完整版PPT课件
- 28科学发展盐城巨变
- 南盘江特大桥设计要点及主要施工方案初步研究
- (完整版)市政道路工程施工质量验收规程(DB13(J)55-2005)
评论
0/150
提交评论