计循环链表与双向链表及线性表的应用举例
[转载整理]C语言链表实例
[转载整理]C语⾔链表实例 C语⾔链表有单链表、双向链表、循环链表。
单链表由数据域和指针域组成,数据域存放数据,指针域存放该数据类型的指针便于找到下⼀个节点。
双链表则含有头指针域、数据域和尾指针域,域单链表不同,双链表可以从后⼀个节点找到前⼀个节点,⼆单链表则不⾏。
循环链表就是在单链表的基础上,将头结点的地址指针存放在最后⼀个节点的指针域⾥以,此形成循环。
此外还有双向循环链表,它同时具有双向链表和循环链表的功能。
单链表如:链表节点的数据结构定义struct node{int num;struct node *p;} ;在此链表节点的定义中,除⼀个整型的成员外,成员p是指向与节点类型完全相同的指针。
※在链表节点的数据结构中,⾮常特殊的⼀点就是结构体内的指针域的数据类型使⽤了未定义成功的数据类型。
这是在C中唯⼀规定可以先使⽤后定义的数据结构。
链表实例代码:1// 原⽂地址 /wireless-dragon/p/5170565.html2 #include<stdio.h>3 #include<stdlib.h>4 #include<string.h>56 typedef int elemType;//定义存⼊的数据的类型可以是int char78 typedef struct NODE{ //定义链表的结构类型9 elemType element;10struct NODE *next;11 }Node;1213/************************************************************************/14/* 以下是关于线性表链接存储(单链表)操作的19种算法 */1516/* 1.初始化线性表,即置单链表的表头指针为空 */17/* 2.创建线性表,此函数输⼊负数终⽌读取数据*/18/* 3.打印链表,链表的遍历*/19/* 4.清除线性表L中的所有元素,即释放单链表L中所有的结点,使之成为⼀个空表 */20/* 5.返回单链表的长度 */21/* 6.检查单链表是否为空,若为空则返回1,否则返回0 */22/* 7.返回单链表中第pos个结点中的元素,若pos超出范围,则停⽌程序运⾏ */23/* 8.从单链表中查找具有给定值x的第⼀个元素,若查找成功则返回该结点data域的存储地址,否则返回NULL */24/* 9.把单链表中第pos个结点的值修改为x的值,若修改成功返回1,否则返回0 */25/* 10.向单链表的表头插⼊⼀个元素 */26/* 11.向单链表的末尾添加⼀个元素 */27/* 12.向单链表中第pos个结点位置插⼊元素为x的结点,若插⼊成功返回1,否则返回0 */28/* 13.向有序单链表中插⼊元素x结点,使得插⼊后仍然有序 */29/* 14.从单链表中删除表头结点,并把该结点的值返回,若删除失败则停⽌程序运⾏ */30/* 15.从单链表中删除表尾结点并返回它的值,若删除失败则停⽌程序运⾏ */31/* 16.从单链表中删除第pos个结点并返回它的值,若删除失败则停⽌程序运⾏ */32/* 17.从单链表中删除值为x的第⼀个结点,若删除成功则返回1,否则返回0 */33/* 18.交换2个元素的位置 */34/* 19.将线性表进⾏冒排序 */35363738/*注意检查分配到的动态内存是否为空*/3940414243/* 1.初始化线性表,即置单链表的表头指针为空 */44void initList(Node **pNode)45 {46 *pNode=NULL;47 printf("initList函数执⾏,初始化成功\n");48 }4950/* 2.创建线性表,此函数输⼊负数终⽌读取数据*/51 Node *creatList(Node *pHead)52 {53 Node *p1,*p2;54 p1=p2=(Node *)malloc(sizeof(Node));55if(p1 == NULL || p2 ==NULL)57 printf("内存分配失败\n");58 exit(0);59 }60 memset(p1,0,sizeof(Node));6162 scanf("%d",&p1->element);63 p1->next=NULL;6465while(p1->element >0) //输⼊的值⼤于0则继续,否则停⽌66 {67if(pHead == NULL)//空表,接⼊表头68 {69 pHead=p1;70 }71else72 {73 p2->next=p1;74 }7576 p2=p1;77 p1=(Node *)malloc(sizeof(Node));7879if(p1==NULL||p2==NULL)80 {81 printf("内存分配失败\n");82 exit(0);83 }84 memset(p1,0,sizeof(Node));85 scanf("%d",&p1->element);86 p1->next=NULL;87 }88 printf("CreatList函数执⾏,链表创建成功\n");89return pHead;90 }9192/* 3.打印链表,链表的遍历*/93void printList(Node *pHead)94 {95if(NULL==pHead)96 {97 printf("PrintList函数执⾏,链表为空\n");98 }99else100 {101while(NULL!=pHead)102 {103 printf("%d\n",pHead->element);104 pHead=pHead->next;105 }106 }107108 }109110111/* 4.清除线性表L中的所有元素,即释放单链表L中所有的结点,使之成为⼀个空表 */ 112void clearList(Node *pHead)113 {114 Node *pNext;115116if(pHead==NULL)117 {118 printf("clearList函数执⾏,链表为空\n");119return;120 }121while(pHead->next!=NULL)122 {123 pNext=pHead->next;124free(pHead);125 pHead=pNext;126 }127 printf("clearList函数执⾏,链表已经清除!\n");128129 }130131/* 5.返回链表的长度*/132int sizeList(Node *pHead)133 {134int size=0;135136while(pHead!=NULL)137 {138 size++;139 pHead=pHead->next;141 printf("sizelist函数执⾏,链表长度为%d\n",size);142return size;143 }144145/* 6.检查单链表是否为空,若为空则返回1,否则返回0 */146int isEmptyList(Node *pHead)147 {148if(pHead==NULL)149 {150 printf("isEmptylist函数执⾏,链表为空!\n");151return1;152 }153154else155 printf("isEmptylist函数执⾏,链表⾮空!\n");156return0;157158 }159160/* 7.返回链表中第post节点的数据,若post超出范围,则停⽌程序运⾏*/161int getElement(Node *pHead,int pos)162 {163int i=0;164if(pos<1)165 {166 printf("getElement函数执⾏,pos值⾮法!");167return0;168 }169if(pHead==NULL)170 {171 printf("getElement函数执⾏,链表为空!");172 }173174while (pHead!=NULL)175 {176 ++i;177if(i==pos)178 {179break;180 }181 pHead=pHead->next;182 }183if(i<pos)184 {185 printf("getElement函数执⾏,pos值超出链表长度\n");186return0;187 }188 printf("getElement函数执⾏,位置%d中的元素为%d\n",pos,pHead->element);189190return1;191 }192193//8.从单⼀链表中查找具有给定值x的第⼀个元素,若查找成功后,返回该节点data域的存储位置,否则返回NULL 194 elemType *getElemAddr(Node *pHead,elemType x)195 {196if(NULL==pHead)197 {198 printf("getEleAddr函数执⾏,链表为空");199return NULL;200 }201if(x<0)202 {203 printf("getEleAddr函数执⾏,给定值x不合法\n");204return NULL;205 }206while((pHead->element!=x)&&(NULL!=pHead->next))//判断链表是否为空,并且是否存在所查找的元素207 {208 pHead=pHead->next;209 }210if(pHead->element!=x)211 {212 printf("getElemAddr函数执⾏,在链表中没有找到x值\n");213return NULL;214 }215else216 {217 printf("getElemAddr函数执⾏,元素%d的地址为0x%x\n",x,&(pHead->element));218 }219return &(pHead->element);220221 }222223224/*9.修改链表中第pos个点X的值,如果修改成功,则返回1,否则返回0*/225int modifyElem(Node *pNode,int pos,elemType x)226 {227 Node *pHead;228 pHead=pNode;229int i=0;230if(NULL==pHead)231 {232 printf("modifyElem函数执⾏,链表为空\n");233return0;234 }235236if(pos<1)237 {238 printf("modifyElem函数执⾏,pos值⾮法\n");239return0;240 }241242while(pHead!= NULL)243 {244 ++i;245if(i==pos)246 {247break;248 }249 pHead=pHead->next;250 }251252if(i<pos)253 {254 printf("modifyElem函数执⾏,pos值超出链表长度\n");255return0;256 }257 pNode=pHead;258 pNode->element=x;259 printf("modifyElem函数执⾏,修改第%d点的元素为%d\n",pos,x);260261return1;262263 }264265/* 10.向单链表的表头插⼊⼀个元素 */266int insertHeadList(Node **pNode,elemType insertElem)267 {268 Node *pInsert;269 pInsert=(Node *)malloc(sizeof(Node));270if(pInsert==NULL) exit(1);271 memset(pInsert,0,sizeof(Node));272 pInsert->element=insertElem;273 pInsert->next=*pNode;274 *pNode=pInsert;275 printf("insertHeadList函数执⾏,向表头插⼊元素%d成功\n",insertElem);276return1;277 }278279/* 11.向单链表的末尾添加⼀个元素 */280int insertLastList(Node *pNode,elemType insertElem)281 {282 Node *pInsert;283 Node *pHead;284 Node *pTmp;285286 pHead=pNode;287 pTmp=pHead;288 pInsert=(Node *)malloc(sizeof(Node));289if(pInsert==NULL) exit(1);290 memset(pInsert,0,sizeof(Node));291 pInsert->element=insertElem;292 pInsert->next=NULL;293while(pHead->next!=NULL)294 {295 pHead=pHead->next;296 }297 pHead->next=pInsert;298 printf("insertLastList函数执⾏,向表尾插⼊元素%d成功!\n",insertElem);299return1;300 }301302/* 12.向单链表中第pos个结点位置插⼊元素为x的结点,若插⼊成功返回1,否则返回0*/ 303int isAddPos(Node *pNode,int pos,elemType x)304 {305 Node *pHead;306 pHead=pNode;307 Node *pTmp;308int i=0;309310if(NULL==pHead)311 {312 printf("AddPos函数执⾏,链表为空\n");313return0;314 }315316if(pos<1)317 {318 printf("AddPos函数执⾏,pos值⾮法\n");319return0;320 }321322while(pHead!=NULL)323 {324 ++i;325if(i==pos)326break;327 pHead=pHead->next;328 }329330if(i<pos)331 {332 printf("AddPos函数执⾏,pos值超出链表长度\n");333return0;334 }335336 pTmp=(Node *)malloc(sizeof(Node));337if(pTmp==NULL) exit(1);338 memset(pTmp,0,sizeof(Node));339 pTmp->next=pHead->next;340 pHead->next=pTmp;341 pTmp->element=x;342343 printf("AddPos函数执⾏成功,向节点%d后插⼊数值%d\n",pos,x); 344return1;345 }346347/* 13.向有序单链表中插⼊元素x结点,使得插⼊后仍然有序 */348int OrrderList(Node *pNode,elemType x)349 {350//注意如果此数值要排到⾏尾要修改本代码351 Node *pHead;352 pHead=pNode;353 Node *pTmp;354355if(NULL==pHead)356 {357 printf("OrrderList函数执⾏,链表为空\n");358return0;359 }360361if(x<1)362 {363 printf("OrrderList函数执⾏,x值⾮法\n");364return0;365 }366367while(pHead!=NULL)368 {369if((pHead->element)>=x)370break;371 pHead=pHead->next;372 }373374375if(pHead==NULL)376 {377 printf("OrrderList函数查找完毕,该函数中没有该值\n");378return0;379 }380381382 pTmp=(Node *)malloc(sizeof(Node));383if(pTmp==NULL) exit(1);384 memset(pTmp,0,sizeof(Node));385 pTmp->next=pHead->next;386 pHead->next=pTmp;387 pTmp->element=x;388389 printf("OrrderList函数成功插⼊数值%d\n",x);390return1;391 }392393/*14.从单链表中删除表头结点,并把该结点的值返回,若删除失败则停⽌程序运⾏*/ 394int DelHeadList(Node **pList)395 {396 Node *pHead;397 pHead=*pList;398if(pHead!=NULL)399 printf("DelHeadList函数执⾏,函数⾸元素为%d删除成功\n",pHead->element); 400else401 {402 printf("DelHeadList函数执⾏,链表为空!");403return0;404 }405 *pList=pHead->next;406return1;407 }408409/* 15.从单链表中删除表尾结点并返回它的值,若删除失败则停⽌程序运⾏ */410int DelLastList(Node *pNode)411 {412 Node *pHead;413 Node *pTmp;414415 pHead=pNode;416while(pHead->next!=NULL)417 {418 pTmp=pHead;419 pHead=pHead->next;420 }421 printf("链表尾删除元素%d成功!\n",pHead->element);422free(pHead);423 pTmp->next=NULL;424return1;425 }426427/* 16.从单链表中删除第pos个结点并返回它的值,若删除失败则停⽌程序运⾏ */ 428int DelPos(Node *pNode,int pos)429 {430 Node *pHead;431 pHead=pNode;432 Node *pTmp;433434int i=0;435436if(NULL==pHead)437 {438 printf("DelPos函数执⾏,链表为空\n");439return0;440 }441442if(pos<1)443 {444 printf("DelPos函数执⾏,pos值⾮法\n");445return0;446 }447448while(pHead!=NULL)449 {450 ++i;451if(i==pos)452break;453 pTmp=pHead;454 pHead=pHead->next;455 }456457if(i<pos)458 {459 printf("DelPos函数执⾏,pos值超出链表长度\n");460return0;461 }462 printf("DelPos函数执⾏成功,节点%d删除数值%d\n",pos,pHead->element); 463 pTmp->next=pHead->next;464free(pHead);465return1;466 }467468/* 17.从单链表中删除值为x的第⼀个结点,若删除成功则返回1,否则返回0 */469int Delx(Node **pNode,int x)470 {471 Node *pHead;472 Node *pTmp;473 pHead=*pNode;474int i=0;475476if(NULL==pHead)477 {478 printf("Delx函数执⾏,链表为空");479return0;480 }481if(x<0)482 {483 printf("Delx函数执⾏,给定值x不合法\n");484return0;485 }486while((pHead->element!=x)&&(NULL!=pHead->next))//判断链表是否为空,并且是否存在所查找的元素487 {488 ++i;489 pTmp=pHead;490 pHead=pHead->next;491 }492if(pHead->element!=x)493 {494 printf("Delx函数执⾏,在链表中没有找到x值\n");495return0;496 }497if((i==0)&&(NULL!=pHead->next))498 {499 printf("Delx函数执⾏,在链表⾸部找到此元素,此元素已经被删除\n");500 *pNode=pHead->next;501free(pHead);502return1;503 }504 printf("Delx函数执⾏,⾸个为%d元素被删除\n",x);505 pTmp->next=pHead->next;506free(pHead);507return1;508 }509510/* 18.交换2个元素的位置 */511int exchange2pos(Node *pNode,int pos1,int pos2)512 {513 Node *pHead;514int *pTmp;515int *pInsert;516int a;517int i=0;518519if(pos1<1||pos2<1)520 {521 printf("DelPos函数执⾏,pos值⾮法\n");522return0;523 }524525 pHead=pNode;526while(pHead!=NULL)527 {528 ++i;529if(i==pos1)530break;531 pHead=pHead->next;532 }533534if(i<pos1)535 {536 printf("DelPos函数执⾏,pos1值超出链表长度\n");537return0;538 }539540 pTmp=&(pHead->element);541 i=0;542 pHead=pNode;543while(pHead!=NULL)544 {545 ++i;546if(i==pos2)547break;548 pHead=pHead->next;549 }550551if(i<pos2)552 {553 printf("DelPos函数执⾏,pos2值超出链表长度\n");554return0;555 }556557 pInsert=&(pHead->element);558 a=*pTmp;559 *pTmp=*pInsert;560 *pInsert=a;561562 printf("DelPos函数执⾏,交换第%d个和第%d个pos点的值\n",pos1,pos2); 563return1;564 }565566int swap(int *p1,int *p2)567 {568int a;569if(*p1>*p2)570 {571 a=*p1;572 *p1=*p2;573 *p2=a;574 }575return0;576 }577578/* 19.将线性表进⾏冒泡排序 */579int Arrange(Node *pNode)580 {581 Node *pHead;582 pHead=pNode;583584int a=0,i,j;585586if(NULL==pHead)587 {588 printf("Arrange函数执⾏,链表为空\n");589return0;590 }591592while(pHead!=NULL)593 {594 ++a;595 pHead=pHead->next;596 }597598 pHead=pNode;599for(i=0;i<a-1;i++)600 {601for(j=1;j<a-i;j++)602 {603 swap(&(pHead->element),&(pHead->next->element));604 pHead=pHead->next;605 }606 pHead=pNode;607 }608 printf("Arrange函数执⾏,链表排序完毕!\n");609return0;610 }611612int main()613 {614 Node *pList=NULL;615int length=0;616617 elemType posElem;618619 initList(&pList);620 printList(pList);621622 pList=creatList(pList);623 printList(pList);624625 sizeList(pList);626 printList(pList);627628 isEmptyList(pList);629630631 posElem=getElement(pList,3);632 printList(pList);633634 getElemAddr(pList,5);635636 modifyElem(pList,4,1);637 printList(pList);638639 insertHeadList(&pList,5);640 printList(pList);641642 insertLastList(pList,10);643 printList(pList);644645 isAddPos(pList,4,5); 646 printList(pList);647648 OrrderList(pList,6);649 printList(pList);650651 DelHeadList(&pList); 652 printList(pList);653654 DelLastList(pList);655 printList(pList);656657 DelPos(pList,5);658 printList(pList);659660 Delx(&pList,5);661 printList(pList);662663 exchange2pos(pList,2,5); 664 printList(pList);665666 Arrange(pList);667 printList(pList);668669 clearList(pList);670return0;671 }。
链表应用场景
链表应用场景链表是一种常见的数据结构,在计算机科学的多个领域都有广泛应用。
下面将介绍链表在不同领域的应用场景。
1.数据库索引在数据库中,索引用于加快查询速度。
传统的数据库索引是基于B+树的,但是如果需要频繁地插入和删除数据,B+树的修改和维护成本较高。
链表索引结构的修改方便,尤其适合多次插入和删除操作的场景,因此链表索引在部分数据库中被使用。
2.编辑器撤销操作编辑器通常有撤销操作,这就需要一种能够高效插入和删除数据的数据结构。
链表由于支持O(1)时间内插入或删除某个元素,因此也是编辑器中实现撤销操作的常用数据结构。
3.内存管理链表在内存管理中有广泛应用,比如操作系统中的内存管理器。
操作系统会将内存划分成多个块,每个块对应一个页框,然后使用链表来管理这些页框。
当有一个进程需要申请内存时,操作系统可以快速分配一个空闲页框。
4.垃圾回收在面向对象的编程语言中,垃圾回收器会定期扫描堆内存中的对象,将未被引用的对象标记为垃圾并回收掉。
垃圾回收器使用链表来管理内存池,以便快速查找空闲对象、回收内存等。
5.图形学在图形学中,遍历图像的像素的顺序很重要。
一些算法需要按照特定的顺序访问像素,比如计算图像的梯度、滤波、深度优先遍历等。
链表的任意访问特性使得其在图形学中的应用非常广泛。
6.缓存链表也常被用于实现缓存。
客户端向服务器请求数据时,服务器将数据缓存在链表中。
当客户端再次请求相同的数据时,服务器可以快速地将数据返回,无需再次生成。
链表也非常适合访问频率比较低的数据,可以将这些数据缓存到链表中,避免反复查找。
7.实现队列和栈链表也可以用来实现队列和栈的数据结构。
队列和栈在编程中经常被用到,比如在实现广度优先搜索算法时需要用到队列,而深度优先搜索算法需要使用栈。
利用链表实现队列和栈时,插入和删除元素的时间复杂度都是O(1),能够满足数据结构中常规的操作。
8.视频播放在视频播放器中,将视频分为小的数据块,再用链表依次连接。
掌握数据结构中的链表和数组的应用场景
掌握数据结构中的链表和数组的应用场景链表和数组都是常用的数据结构,它们在不同的场景下有不同的应用。
一、链表的应用场景:1.链表适合动态插入和删除操作:链表的插入和删除操作非常高效,只需修改指针的指向,时间复杂度为O(1)。
因此,当需要频繁进行插入和删除操作时,链表是一个很好的选择。
-操作系统中的进程控制块(PCB):操作系统需要频繁地创建、停止、销毁进程,使用链表存储这些PCB,可以方便地插入、删除和管理进程。
-聊天记录:在聊天应用中,新的消息会动态插入到聊天记录中,使用链表存储聊天记录可以方便地插入新消息。
2.链表节省内存空间:每个节点只需存储当前元素和指向下一个节点的指针,不需要像数组一样预分配一块连续的内存空间,因此链表对内存空间的利用更加灵活。
-操作系统中的内存管理:操作系统使用链表来管理空闲内存块和已分配的内存块,可有效节省内存空间。
3.链表支持动态扩展:链表的长度可以随时变化,可以动态地扩容和缩容。
-缓存淘汰算法:在缓存中,如果链表已满,当有新数据需要加入缓存时,可以通过删除链表头部的节点来腾出空间。
4.链表可以快速合并和拆分:将两个链表合并成一个链表只要调整指针的指向即可,时间复杂度为O(1)。
-链表排序:在排序算法中,链表归并排序利用链表快速合并的特性,使得归并排序在链表上更高效。
二、数组的应用场景:1.随机访问:数组可以根据索引快速访问元素,时间复杂度为O(1)。
-图像处理:图像通常以像素点的形式存储在数组中,可以通过索引快速访问某个特定像素点的颜色信息。
2.内存连续存储:数组的元素在内存中是连续存储的,可以利用硬件缓存机制提高访问效率。
-矩阵运算:矩阵可以通过二维数组来表示,利用矩阵的连续存储特性,可以高效地进行矩阵运算。
3.大数据存储:数组可以预先分配一块连续的内存空间,非常适合存储大量的数据。
-数据库中的数据表:数据库中的数据表通常使用数组来实现,可以快速存取和处理大量的数据。
数据结构线性表应用
数据结构线性表应用在计算机科学领域中,数据结构是一门至关重要的学科,它为我们提供了高效组织和管理数据的方法。
其中,线性表作为一种基本的数据结构,具有广泛的应用场景。
线性表是由零个或多个数据元素组成的有限序列。
这些数据元素在逻辑上是线性排列的,也就是说,它们之间存在着一种顺序关系。
常见的线性表实现方式有顺序表和链表。
顺序表是一种采用连续存储空间来存储数据元素的线性表。
它的优点是可以随机访问元素,时间复杂度为 O(1)。
这意味着,如果我们知道元素在顺序表中的位置,就能够快速地获取到该元素。
想象一下,我们有一个学生成绩的顺序表,要查找第 10 个学生的成绩,直接根据索引就能迅速找到。
顺序表在需要频繁进行随机访问的场景中表现出色,比如在数据库中存储数据时。
然而,顺序表也有它的局限性。
当需要插入或删除元素时,如果插入或删除的位置不是在表尾,就需要移动大量的元素,时间复杂度为O(n)。
这在数据量较大时,可能会导致性能下降。
相比之下,链表则在插入和删除操作上具有优势。
链表中的每个节点包含数据元素和指向下一个节点的指针。
当进行插入或删除操作时,只需要修改相关节点的指针即可,时间复杂度为 O(1)。
比如,在一个购物车的链表中,添加或删除商品时,不需要移动其他商品的位置,操作效率很高。
线性表在日常生活中的应用比比皆是。
以我们常见的排队为例,排队的人群可以看作是一个线性表。
每个人按照先后顺序排列,新加入的人排在队尾,离开的人从队首离开。
这种先入先出的特性,与线性表中的队列结构相似。
在计算机程序中,线性表也有广泛的应用。
比如,在文本编辑软件中,我们输入的字符序列可以看作是一个线性表。
当我们进行插入、删除字符的操作时,就是对这个线性表进行修改。
再比如,在操作系统的进程管理中,进程可以按照它们的创建顺序或者优先级排列成一个线性表。
操作系统在调度进程时,需要根据线性表中的信息来决定哪个进程先执行,哪个进程后执行。
在软件开发中,线性表也常用于实现栈这种数据结构。
链表生活中举例子
链表生活中举例子链表是一种常见的数据结构,在生活中也有很多类似的例子可以来解释。
下面是符合要求的十个例子:1. 电线路:电线路可以看作是一条链表,电流从一端流向另一端。
每个电线都连接在一起,形成一个链式结构。
如果其中一个电线断开了,电流就无法顺利流通,就像链表中的节点断开一样。
2. 银行排队取款:在银行排队取款时,每个人按照先后顺序站在一起,形成一个队列。
当某个人取完款后,后面的人依次向前移动一个位置,就像链表中的节点删除和插入操作一样。
3. 图书馆书架:图书馆的书架上摆放着很多书籍,每本书都有自己的位置。
当有新书到达时,会被插入到合适的位置上,就像链表中的节点插入操作一样。
4. 手链:手链由一串串的珠子或者链节组成,每个珠子或链节都连接在一起。
当手链被拉伸时,每个珠子或链节都会依次移动,就像链表中的节点遍历一样。
5. 网络游戏中的队伍:在网络游戏中,玩家可以组队进行战斗。
每个队友按照先后顺序排列,形成一个队伍。
当队伍中有人离开或加入时,队伍的成员顺序会发生变化,就像链表中的节点删除和插入操作一样。
6. 交通信号灯:交通信号灯由红、黄、绿三个灯组成,每个灯都有自己的状态。
当信号灯的状态发生变化时,车辆会根据不同的灯光信号做出相应的动作,就像链表中的节点更新操作一样。
7. 餐厅的等候队列:在繁忙的餐厅,人们会排队等候就餐。
每个人按照先后顺序排列,形成一个等候队列。
当有桌子空出来时,排在队列最前面的人会被叫号,就像链表中的节点删除操作一样。
8. 航班座位预订系统:在航班座位预订系统中,每个座位都有自己的状态(已预订、空闲)。
当有人预订座位或取消预订时,座位的状态会发生变化,就像链表中的节点更新操作一样。
9. 电影院的座位安排:在电影院观影时,每个座位都有自己的位置。
当有人购买电影票时,会选择一个座位坐下,就像链表中的节点插入操作一样。
10. 城市地铁线路:城市地铁线路将不同的地铁站连接在一起,形成一个链式结构。
链表在单片机中的应用
链表在单片机中的应用链表是一种数据结构,被广泛应用于计算机编程领域。
在单片机中,链表也有着重要的应用。
下面将从链表的基本概念、实现方式及其在单片机中的应用三个方面进行介绍。
一、链表的基本概念链表是一种由节点构成的数据结构,每个节点包含数据域和指针域。
数据域用于存储数据,指针域则指向下一个节点。
链表中每个节点之间并没有直接的关联,因此在插入、删除等操作时,只需改变节点间的指针即可,不用涉及数据的移动,从而实现高效的操作。
链表可以分为单向链表、双向链表、循环链表等多种类型。
其中,单向链表是指链表中每个节点只有一个指针,指向下一个节点;双向链表则每个节点有两个指针,分别指向前一个和后一个节点;而循环链表则是一种特殊的链表,它的尾节点指向头节点,形成一个环形。
二、链表的实现方式链表的实现方式有两种:静态链表和动态链表。
静态链表是指使用数组实现的链表,每个节点在数组中都有一个预分配的空间,链表中每个节点之间的关联通过下标实现。
而动态链表则是在程序运行时通过动态分配内存来实现的。
动态链表的实现需要用到C语言中的动态内存分配函数malloc和free。
在单片机中,由于内存大小有限,需要特别注意动态链表的内存分配和释放,避免出现内存浪费或内存不足的情况。
三、链表在单片机中的应用链表在单片机中有着广泛的应用,这里只列举了其中几个常见的应用场景:1.存储传感器数据在单片机的嵌入式应用中,需要采集各种传感器数据,如温度、湿度、气压等。
这些数据可以通过链表的形式存储起来,可以方便地进行操作和分析,同时也能节省内存空间。
2.任务调度在单片机中,常常需要同时执行多个任务,这就需要一种任务调度的机制。
链表可以用来存储各个任务,同时根据不同的优先级进行排序。
通过遍历链表,可以按照优先级执行不同的任务,从而实现任务调度的功能。
3.堆栈堆栈是一种后进先出(LIFO)的数据结构,可以用来存储和管理程序执行时需要的临时数据。
链表可以用来实现堆栈,每次入栈或出栈时修改链表的头部指针即可。
第3周线性表(下)第2讲-循环链表
循环链表是另一种形式的链式存储结构形式。
循环单链表:将表中尾节点的指针域改为指向表头节点,整个链表形成一个环。
由此从表中任一节点出发均可找到链表中其他节点。
循环双链表:形成两个环。
节点类型与非循环单链表的相同节点类型与非循环双链表的相同线性表(a 1, a 2, …, a i , … a n )映射逻辑结构存储结构a 1a 2a n…L带头节点循环单链表示意图1、循环单链表与非循环单链表相比,循环单链表:链表中没有空指针域p所指节点为尾节点的条件:p->next==LL pa1a2a n…【例2-8】某线性表最常用的操作是在尾元素之后插入一个元素和删除第一个元素,故采用存储方式最节省运算时间。
A.单链表B.仅有头结点指针的循环单链表C.双链表D.仅有尾结点指针的循环单链表D.仅有尾结点指针的循环单链表a 1a2a n…L在尾元素之后插入一个元素删除第一个元素时间复杂度均为O(1)选择D线性表(a 1, a 2, … , a i , … a n )映射逻辑结构存储结构a 1a 2a n…L带头节点循环双链表示意图2、循环双链表与非循环双链表相比,循环双链表:链表中没有空指针域p所指节点为尾节点的条件:p->next==L一步操作即L->prior可以找到尾节点p La1a2a n…【例2-9】如果对含有n(n>1)个元素的线性表的运算只有4种,即删除第一个元素、删除尾元素、在第一个元素前面插入新元素、在尾元素的后面插入新元素,则最好使用。
A.只有尾结点指针没有头结点的循环单链表B.只有尾结点指针没有头结点的非循环双链表C.只有首结点指针没有尾结点指针的循环双链表D.既有头指针也有尾指针的循环单链表a 1a 2a n…LC.只有首结点指针没有尾结点指针的循环双链表删除第一个元素删除尾元素在第一个元素前面插入新元素在尾元素的后面插入新元素时间复杂度均为O(1)选择C【例2-10】设计判断带头节点的循环双链表L(含两个以上的节点)是否对称相等的算法。
数据结构—链表
数据结构—链表链表⽬录⼀、概述1.链表是什么链表数⼀种线性数据结构。
它是动态地进⾏储存分配的⼀种结构。
什么是线性结构,什么是⾮线性结构?线性结构是⼀个有序数据元素的集合。
常⽤的线性结构有:线性表,栈,队列,双队列,数组,串。
⾮线性结构,是⼀个结点元素可能有多个直接前趋和多个直接后继。
常见的⾮线性结构有:⼆维数组,多维数组,⼴义表,树(⼆叉树等)。
2.链表的基本结构链表由⼀系列节点组成的集合,节点(Node)由数据域(date)和指针域(next)组成。
date负责储存数据,next储存其直接后续的地址3.链表的分类单链表(特点:连接⽅向都是单向的,对链表的访问要通过顺序读取从头部开始)双链表循环链表单向循环链表双向循环链表4.链表和数组的⽐较数组:优点:查询快(地址是连续的)缺点:1.增删慢,消耗CPU内存链表就是⼀种可以⽤多少空间就申请多少空间,并且提⾼增删速度的线性数据结构,但是它地址不是连续的查询慢。
⼆、单链表[1. 认识单链表](#1. 认识单链表)1. 认识单链表(1)头结点:第0 个节点(虚拟出来的)称为头结点(head),它没有数据,存放着第⼀个节点的⾸地址(2)⾸节点:第⼀个节点称为⾸节点,它存放着第⼀个有效的数据(3)中间节点:⾸节点和接下来的每⼀个节点都是同⼀种结构类型:由数据域(date)和指针域(next)组成数据域(date)存放着实际的数据,如学号(id)、姓名(name)、性别(sex)、年龄(age)、成绩(score)等指针域(next)存放着下⼀个节点的⾸地址(4)尾节点:最后⼀个节点称为尾节点,它存放着最后⼀个有效的数据(5)头指针:指向头结点的指针(6)尾指针:指向尾节点的指针(7)单链表节点的定义public static class Node {//Object类对象可以接收⼀切数据类型解决了数据统⼀问题public Object date; //每个节点的数据Node next; //每个节点指向下⼀结点的连接public Node(Object date) {this.date = date;}}2.引⼈头结点的作⽤1. 概念头结点:虚拟出来的⼀个节点,不保存数据。
数据结构-chap2 (3)循环链表
head->next=NULL; while(p!=NULL) {r=p->next; head->next=p; p=r; } return(head); }∥invert
∥p为工作指针,指向第一个元素
∥臵空链表 ∥将原链表的元素按头插法插入 ∥暂存p的后继 ∥头结点的指针域指向新插入的结点 ∥恢复待处理结点
A.插入、删除不需要移动元素
B.可随机访问任一元素 C.不必事先估计存储空间 D.所需空间与线性长度成正比
试述头指针、头结点、元素结点、首元结点的区别。 单链表中,增加一个头结点的目的是为了( )。 【江苏大学 2005 一.3(2分)】 A.使单链表至少有一个结点 B.标识表结点中首结点的位臵
C.方便运算的实现
【解答】单循环链表中无论设置尾指针还是头指针都可以
遍历到表中任一个结点。设置尾指针时,若在表尾进行插 入元素或删除第一元素,操作可在O(1)时间内完成;若只 设置头指针,在表尾进行插入或删除操作,需要遍历整个 链表,时间复杂度为O(n)。
在循环链表中寻找结点的直接后继很简单,只需要O(1); 但要寻找结点的直接前趋需要循环一遍,需要O(n)。
C. (p->rlink)->llink=p
D. p->rlink=(p->llink)->llink
p->rlink=(p->rlink)->rlink
p->llink=(p->rlink)->rlink;
【西安电子科技大学 1998 一、1(2分)】
试述头指针、头结点、元素结点、首元结点的区别。 •在单链表、双链表、单循环链表中,若知道指针p指向某结点, 能否删除该结点,时间复杂度如何? 【解答】以上三种链表中,若知道指针p指向某结点,都能 删除该结点。
数据结构中的双向链表实现和应用场景
数据结构中的双向链表实现和应用场景双向链表是一种常用的数据结构,它在许多实际应用中都发挥着重要的作用。
本文将介绍双向链表的实现原理以及一些常见的应用场景。
一、双向链表的实现原理双向链表由一系列节点组成,每个节点包含两个指针,一个指向前一个节点,一个指向后一个节点。
相比于单向链表,双向链表可以实现双向遍历,提高了一些操作的效率。
1.1 节点定义双向链表的节点通常由数据域和两个指针域组成,例如:```struct Node {int data; // 节点数据Node* prev; // 前一个节点指针Node* next; // 后一个节点指针};```1.2 插入操作在双向链表中插入一个节点可以分为两种情况:在表头插入和在表尾插入。
在表头插入时,只需修改原来头节点的prev指针为新节点的地址,并将新节点的next指针指向原头节点即可。
在表尾插入时,需要先找到原来的尾节点,然后将尾节点的next指针指向新节点的地址,并将新节点的prev指针指向尾节点的地址。
1.3 删除操作删除操作与插入操作类似,同样分为在表头和表尾删除节点。
在表头删除时,只需将头节点的next指针指向新的头节点,同时将新头节点的prev指针置为空。
在表尾删除时,需要先找到尾节点的前一个节点,然后将该节点的next指针置为空。
1.4 查找操作双向链表支持从前向后和从后向前两种遍历方式。
从前向后遍历时,我们可以利用节点的next指针不断向后遍历得到所有节点。
同样,从后向前遍历时,可以利用节点的prev指针不断向前遍历得到所有节点。
二、双向链表的应用场景双向链表广泛应用于各种软件和系统中,下面列举了一些常见的应用场景。
2.1 浏览器的历史记录在浏览器中,经常需要记录用户浏览过的网页历史记录。
这时可以使用双向链表来实现。
每当用户访问一个新的网页,就在双向链表中插入一个新节点,同时将新节点的next指针指向前一个节点,prev指针指向后一个节点。
数据结构--数组、单链表和双链表介绍以及双向链表
数据结构--数组、单链表和双链表介绍以及双向链表数组:数组有上界和下界,数组的元素在上下界内是连续的。
数组的特点是:数据是连续的;随机访问速度快。
数组中稍微复杂⼀点的是多维数组和动态数组。
对于C语⾔⽽⾔,多维数组本质上也是通过⼀维数组实现的。
⾄于动态数组,是指数组的容量能动态增长的数组;对于C语⾔⽽⾔,若要提供动态数组,需要⼿动实现;⽽对于C++⽽⾔,STL提供了Vector。
单向链表:单向链表(单链表)是链表的⼀种,它由节点组成,每个节点都包含下⼀个节点的指针。
表头为空,表头的后继节点是"节点10"(数据为10的节点),"节点10"的后继节点是"节点20"(数据为10的节点),"节点20"的后继节点是"节点30"(数据为20的节点),"节点30"的后继节点是"节点40"(数据为10的节点),......删除"节点30"删除之前:"节点20" 的后继节点为"节点30",⽽"节点30" 的后继节点为"节点40"。
删除之后:"节点20" 的后继节点为"节点40"。
在"节点10"与"节点20"之间添加"节点15"添加之前:"节点10" 的后继节点为"节点20"。
添加之后:"节点10" 的后继节点为"节点15",⽽"节点15" 的后继节点为"节点20"。
单链表的特点是:节点的链接⽅向是单向的;相对于数组来说,单链表的的随机访问速度较慢,但是单链表删除/添加数据的效率很⾼。
第二章 指针与链表
第二章指针与链表一、静态存贮和动态存贮1、静态存贮程序中的变量一经说明,计算机操作系统就会在内存空间中分配相应的存贮单元,其中变量名是存贮单元的地址,而变量的值是存贮单元的内容,且该存贮单元自始至终都被该变量所占用,直到程序结束。
如果变量是局部变量,那么在它的作用域内,一经说明也占有一定的存贮单元,直到退出其作用域为止。
这样的变量,在程序执行过程中,不能随时使用随时分配存贮空间,也不能在程序执行的过程中,释放这些空间。
也就是说,一旦给这些变量分配存贮空间,无论程序是否还需要使用,它们都要占用一定的存贮空间,以便给用户存贮数据。
我们称具有这样特点的存贮为静态存贮,它所对应的变量称为静态变量。
如字符类型、数组类型、记录类型等。
这类变量的优点是存贮方便,查找容易,可以通过一个简单的公式随机存取表中的任一元素,逻辑关系上相邻的两个元素在物理位置上也是相邻的,很容易找到前趋与后继元素;缺点是在线性表的长度不确定时,必须分配足够大的存储空间,经常浪费了宝贵的存储资源;而线性表的容量一经定义确定后就难以扩充;在插入和删除线性表的元素时,需要移动大量的元素,时间效率也比较差。
2、动态存贮在程序执行过程中,通过向操作系统申请存贮空间或释放存贮空间的命令,达到动态管理计算机的存贮空间,以保证存贮空间的充分利用。
存贮空间可以随时申请、随时释放,这样的存贮方式称为动态存贮,其变量称为动态变量。
指针变量即为动态变量。
动态存储所需要的空间可以是不连续的,这样有利于充分利用零散的小空间。
但缺无法用O(1)的时间实现存取了。
如何用这些零散的空间存储数组这些大规模数据呢?如何表示这些数据之间的逻辑关系呢?为了表示这些物理存储单元之间的逻辑关系,对于每个数据元素来说,除了要存储它本身的信息(数据域data)外,还要存储它的直接后继元素的存储位置(指针域,一般用link 或next 表示)。
我们往往把这两部分信息合在一起称为一个“结点node”。
多重链表的结构及应用
多重链表的结构及应用一、概述多重链表是一种特殊的链表结构,每个节点可以有多个指针域,用于指向不同的节点。
它可以用来表示复杂的数据结构,例如树和图等。
在实际应用中,多重链表可以用于实现各种数据结构和算法,例如哈希表、图遍历和拓扑排序等。
二、多重链表的定义多重链表由一个头指针和若干个节点组成。
每个节点包含若干个指针域和一个数据域。
指针域用于指向其他节点,数据域存储节点的数据。
三、多重链表的分类1. 单向多重链表:每个节点只有一个指针域,用于指向下一个节点。
2. 双向多重链表:每个节点有两个指针域,分别用于指向前一个节点和后一个节点。
3. 循环多重链表:最后一个节点的指针域指向第一个节点,形成一个环形结构。
4. 带头结点的多重链表:在头部添加一个空节点作为头结点,方便对链表进行操作。
四、多重链表的应用1. 哈希表:哈希表是一种高效的查找算法,在实现过程中需要使用到多重链表来解决冲突问题。
2. 图遍历:图是一种复杂的数据结构,可以用多重链表来表示。
在进行图遍历时,需要使用到深度优先搜索和广度优先搜索算法,这两种算法都需要使用到多重链表来存储节点信息。
3. 拓扑排序:拓扑排序是一种有向无环图的排序算法,在实现过程中需要使用到多重链表来存储节点信息。
4. 文件系统:文件系统是一种树形结构,可以用多重链表来表示。
在实现过程中,需要使用到双向多重链表来维护文件的父子关系和兄弟关系。
5. 文本编辑器:文本编辑器是一种常见的应用程序,可以用多重链表来实现撤销和重做功能。
在实现过程中,需要使用到循环多重链表来维护撤销和重做操作。
五、多重链表的优缺点1. 优点:(1)可以表示复杂的数据结构;(2)方便实现各种算法和数据结构;(3)灵活性高,可以根据需求灵活调整指针域。
2. 缺点:(1)空间复杂度高;(2)访问节点时需要遍历指针域;(3)容易出现指针错误。
六、总结多重链表是一种特殊的链表结构,可以用于表示复杂的数据结构和实现各种算法和数据结构。
循环链表和双向链表
b.head->next = NULL; //此时,b中已只剩第一个结点(头), 为其置空表标志
return k; //返回结果链表中的元素个数
}
为了进一步说明上述程序,举一个程序运行的例子, 其各次循环的运行结果如图5-6所示
p
7 0 3 2 -9 3 1 5
^
(a)A(x)=p5(x)=7+3x2-9x3+x5,进入循环前
该程序不断比较A链和B链中的一对结点的指数值 (称其为当前结点)。开始时A链和B链中参加比较
的当前结点都是它们的第一个元素。
主循环while结束后,可能出现下列3种情况:①A
链和B链同时被处理完;②只有B链处理完;③只有A
链处理完。 对第一和第二种情况,不需要“善后”处理。对第 三种情况,B链中尚有未被处理完的结点,需将其挂 接在结果链的尾部。循环外的“if(q 不为空)将q
p = p->next; } // if (x==0) … else … q0 = q; q = q->next; delete q0; //将q所指结点从表中删除并释放,令q新指向原所 指的下一个 } // if (p->exp > q->exp ) … else … } //while if (q!=NULL) p0->next = q;
为处理方便,在具体存储多项式时,我们规定:
所存储的多项式已约简,即已合并同类项,不 保留0系数项,各项按指数的升序排列。 (二)多项式加法实现—直接操作链表 为操作方便,我采用带头结点的非循环链表,下面给 出一个例子说明多项式的这种表示法。
设有一个一元5次多项式: P5(x)=7+3x-9x3+x5
链表的概念和应用
链表的概念和应用链表概念和应用链表是计算机科学中经常使用的数据结构,它可以用来管理大量数据,是非常重要的。
链表是一组有序的数据项的集合,每个数据项都包含了数据本身和一个指向下一个数据项的引用。
链表的数据项通过指针进行连接,形成一个链式结构。
链表可以用来存储和操作一组动态的数据集。
链表的结构和在内存中的存储方式,相对于其他线性数据结构(如数组),有一些优势。
最重要的是,在链表的结构中,可以实现动态的内存分配,提供了比其他数据结构更加灵活的数据组织方式。
当数据量很大时,链表的效率可能比数组低,但是当需要对数据进行频繁插入、删除等操作时,链表的效率、实用性会更高。
链表结构通常会包含两个重要的基本元素:头部(Head)和节点(Node)。
头部是链表的开始部分,其包含了链表的第一个节点的地址。
节点则包含了需要存储在链表中的数据和指向链表中下一个节点的地址。
链表可以根据头部地址遍历到所有的节点。
链表与数组的区别数组和链表都是用来存储数据的数据结构。
它们之间的区别主要在于数据存储的位置和内存分配方式。
数组数据会被连续存放在内存中,因此寻址非常快。
但是,由于内存块的大小通常会限制数组的大小。
当要插入或删除数据时,移动其他数据也会比较费时。
链表数据则以一种较为灵活的方式存储在内存中,每个数据项都被放置在完全不同的物理存储位置上。
每个节点都包含了指向下一个节点的引用,当需要插入或删除数据时,链表只需要修改指针,速度非常快。
链表的分类链表可分为单向链表、双向链表、循环链表和双向循环链表。
单向链表(Singly linked list):每个节点只有一个指针指向下一个节点,最后一个节点指向空。
双向链表(Doubly linked list):每个节点都有两个指针,一个指向上一个节点,另一个指向下一个节点。
双向链表可以在单向链表的基础上,增加在链表中向前(尾到头)遍历时的效率。
循环链表(Circular linked list):链表中最后一个节点与头节点连接成一个循环结构。
数据结构中链表及常见操作
链表1 定义链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。
由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
在计算机科学中,链表作为一种基础的数据结构可以用来生成其它类型的数据结构。
链表通常由一连串节点组成,每个节点包含任意的实例数据(data fields)和一或两个用来指向明上一个或下一个节点的位置的链接("links")。
链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的访问往往要在不同的排列顺序中转换。
而链表是一种自我指示数据类型,因为它包含指向另一个相同类型的数据的指针(链接)。
链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。
链表有很多种不同的类型:单向链表,双向链表以及循环链表。
2 结构2.1 单向链表链表中最简单的一种是单向链表,它包含两个域,一个信息域和一个指针域。
这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值。
一个单向链表的节点被分成两个部分。
第一个部分保存或者显示关于节点的信息,第二个部分存储下一个节点的地址。
单向链表只可向一个方向遍历。
链表最基本的结构是在每个节点保存数据和到下一个节点的地址,在最后一个节点保存一个特殊的结束标记,另外在一个固定的位置保存指向第一个节点的指针,有的时候也会同时储存指向最后一个节点的指针。
一般查找一个节点的时候需要从第一个节点开始每次访问下一个节点,一直访问到需要的位置。
链表在现实世界中的应用
链表在现实世界中的应用链表是一种常用的数据结构,它由一系列节点组成,每个节点包含两个部分:数据和指向下一个节点的指针。
链表在计算机科学中被广泛应用于各种场景,而在现实生活中,我们也可以找到许多应用链表的例子:1. 文件系统:在计算机的文件系统中,目录的结构就是一个链表。
每个目录(文件夹)都包含多个文件和子目录。
子目录可以包含更多的文件和子目录,形成了一个层次结构。
这种结构可以用链表来表示,其中每个节点都代表一个目录,节点中的数据部分包含目录的名称,而指针部分指向下一个目录。
2. 网页浏览器的历史记录:当你在网页浏览器中浏览网页时,浏览器的历史记录功能使用链表来记录你访问过的网页。
新访问的网页会被添加到链表的头部,而链表的尾部是你最早访问的网页。
这样,你就可以方便地向前翻页,查看你之前访问过的网页。
3. 电话簿:在电话簿应用中,联系人信息被存储在一个链表中。
每个节点都代表一个联系人,节点中的数据部分包含联系人的姓名和电话号码,指针部分指向下一个联系人。
通过这种方式,你可以方便地按照字母顺序或其他方式浏览联系人列表。
4. 音乐播放器:在许多音乐播放器中,歌曲的播放列表使用链表来组织。
用户可以添加、删除和编辑播放列表,这些操作都可以在链表上方便地实现。
5. 操作系统:在操作系统的进程管理中,链表用于存储正在运行的进程。
每个节点代表一个进程,节点中的数据部分包含进程的状态和相关信息,指针部分指向下一个进程。
操作系统需要经常对链表进行操作,如创建新进程、删除进程和调度进程等。
以上只是链表在现实世界中的一些应用示例,实际上链表的应用非常广泛,它是一种非常有用的数据结构。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
DATA STRUCTURE
数据结构及其基本概念
例、在链表上实现将两个线性表(a1,a2,a3,…an)和(b1,b2, b3,…bn)链接成一个线性表的运算。
typedef struct DuLNode { ElemType data; struct DuLNode *prior; struct DuLNode *next; } DuLNode, *DuLinkList;
DATA STRUCTURE
数据结构及其基本概念
2.3.3双链表
链式存储结构的结点中只有一个指示直接后继的指针域, 因此从某个结点出发只能顺时针往后寻查其它结点。若要寻查 结点的直接前趋,则须从表头指针出发。
DATA STRUCTURE
数据结构及其基本概念
在双向链表中,有些操作如:ListLength、GetElem和LocateElem等仅 需涉及一个方向的指针,则它们的算法描述和线性表的操作相同,但在插 入、删除时有很大的不同,在双向链表中需同时修改两个方向的指针。下 图2.15、2.16所示为在带头结点的双链循环线性表中第i个位置之前插入元素 e和删除带头结点的双链循环线性表L的第i个元素的情况。
DATA STRU结构及其基本概念
循环链表(Circular linked List)时一种头尾相接的链表。 它的特点是表中最后一个结点的指针域指向头结点,整个链表 形成一个环。由此从表中任一结点出发均可找到表中其它结点。
单循环链表:在单链表中,将终端结点的指针域NULL改 为指向表头结点的或开始结点,就得到了单链形式的循环链表, 并简单称为单循环链表。
linklist connect(linklist heada,linklist headb) {
linklist p=heada—>next; heada—>next=(headb—next)—>next free(headb—>next); headb—>next=p; return(headb); }
DATA STRUCTURE
数据结构及其基本概念
和单链表类似,双链表一般也是由头指针唯一确定的,增加头指针也 能使双链表上的某些运算变得方便,将头结点和尾结点链接起来也能构成 循环链表,并称之为双向链表。
设指针p指向某一结点,则双向链表结构的对称性可用下式描述: (p—>prior)—>next=p=(p—>next)—>prior,即结点*p的存储位置既存放在 其前趋结点*(p—>prior)的直接后继指针域中,也存放 在它的后继结点 *(p—>next)的直接前趋指针域中。
free(p);
两个方向上的指针。
}
DATA STRUCTURE
线性表的链式存储结构
拓展思考(典型应用):
1、多项式相加 2、约瑟夫(Joseph)问题
DATA STRUCTURE
为了使空表和非空表的处理一致,循环链表中也可设置一 个头结点。这样,空循环链表仅有一个自成循环的头结点表示。
DATA STRUCTURE
数据结构及其基本概念
循环链表的操作和线性表基本一致,差别仅在于算法中的 循环条件不是p或者p—>next是否为空,而是它们是否等于头 指针。
DATA STRUCTURE
DATA STRUCTURE
数据结构及其基本概念
双向链表的前插操作算法如下:
void dinsertbefor(dlistnode *p,datatype x)
{
dlistnode *q=malloc(sizeof(dlistnode));
q—>data=x;
q—>prior=p—>prior;
q—>next=p;
双向链表(Double linked list):在单链表的每个结点里再增 加一个指向其直接前趋的指针域prior。这样就形成的链表中有 两个方向不同的链,故称为双向链表。形式描述为:
typedef struct DuLNode { ElemType data; struct DuLNode *prior; struct DuLNode *next; } DuLNode, *DuLinkList;
数据结构及其基本概念
在很多实际问题中,表的操作常常是在表的首尾位置上进 行,此时头指针表示的单循环链表就显得不够方便.如果改用尾 指针rear来表示单循环链表,则查找开始结点a1和终端结点an 都很方便,它们的存储位置分别是(rear–>next) —>next和rear, 显然,查找时间都是O(1)。因此,实际中多采用尾指针表示单 循环链表。
p—>prior—>next=q;
p—>prior=q;
}
双向链表的删除操作算法如下: void ddeletenode(dlistnode *p)
{ p–>prior–>next=p–>next; p–>next–>prior=p–>prior;
注意:与单链表的插 入和删除操作不同的 是,在双链表中插入 和删除必须同时修改
DATA STRUCTURE
数据结构及其基本概念
2.3.3双链表
链式存储结构的结点中只有一个指示直接后继的指针域, 因此从某个结点出发只能顺时针往后寻查其它结点。若要寻查 结点的直接前趋,则须从表头指针出发。
双向链表(Double linked list):在单链表的每个结点里再增 加一个指向其直接前趋的指针域prior。这样就形成的链表中有 两个方向不同的链,故称为双向链表。形式描述为:
线性表的链式存储结构
第2章 线性表 (相应教材范围2.3.2-2.4)
教学主题:循环链表与双向链表及线性表的应用举例 教学内容:2.3.2 循环链表;2.3.3 双向链表;2.4 一元多项
式的表示及相加
教学目的:掌握循环链表的概念;掌握双向链表的的表示与实
现;线性表的应用举例
教学重点:双向链表的的表示与实现;线性表的应用举例 教学难点:双向链表的存储表示;线性表的应用举例 教学课时:2