链表的C语言实现之循环链表及双向链表
c语言中linklist类型

c语言中linklist类型LinkList类型是C语言中常用的数据结构之一,它是一种线性链表的实现方式。
在计算机科学中,链表是一种常见的数据结构,用于存储和操作一系列元素。
链表由一系列节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。
链表中的第一个节点称为头节点,最后一个节点称为尾节点。
链表可以根据需要动态地增加或删除节点,相比于数组,链表的大小可以根据实际需求进行调整。
链表的实现可以使用不同的方式,其中最常见的是单向链表。
在单向链表中,每个节点只有一个指针,指向下一个节点。
这种实现方式简单且高效,适用于大多数场景。
除了单向链表,还有双向链表和循环链表等其他实现方式。
链表的优点是可以快速在任意位置插入或删除节点,而无需移动其他节点。
这是由于链表中的节点通过指针相互连接,而不是像数组那样连续存储。
另外,链表的大小可以根据需要进行动态调整,而数组的大小是静态的。
这使得链表在处理动态数据集合时非常有用。
然而,链表也有一些缺点。
首先,访问链表中的任意节点都需要从头节点开始遍历,直到找到目标节点。
这导致了链表的访问时间复杂度为O(n),而数组的访问时间复杂度为O(1)。
其次,链表需要额外的内存空间来存储指针信息,这会占用更多的存储空间。
在C语言中,可以使用结构体来定义链表节点,例如:```typedef struct Node {int data;struct Node *next;} Node;typedef struct LinkedList {Node *head;Node *tail;} LinkedList;```上述代码定义了一个包含数据和指针的节点结构体Node,以及一个包含头节点和尾节点指针的链表结构体LinkedList。
通过这样的定义,可以方便地进行链表的操作,比如插入、删除和遍历等。
链表的插入操作可以分为三步:创建新节点、修改指针、更新链表的头尾指针。
例如,插入一个新节点到链表末尾的代码如下:```void insert(LinkedList *list, int data) {Node *newNode = (Node *)malloc(sizeof(Node));newNode->data = data;newNode->next = NULL;if (list->head == NULL) {list->head = newNode;list->tail = newNode;} else {list->tail->next = newNode;list->tail = newNode;}}```链表的删除操作也类似,可以分为三步:找到目标节点、修改指针、释放内存。
c链表库函数

c链表库函数全文共四篇示例,供读者参考第一篇示例:C语言是一种广泛应用于系统编程的高级语言,而链表(Linked List)是C语言中常用的数据结构之一。
在C语言中,链表并不像数组一样有现成的库函数可以直接调用,需要通过自定义函数来实现链表的操作。
为了方便使用链表,不少开发者封装了链表操作的库函数,提供了一些常用的链表操作接口,以供开发者使用。
本文将介绍一些常见的C链表库函数及其用法。
一、链表的概念及基本操作链表是一种线性表的存储结构,由若干节点(Node)组成,每个节点包含数据域和指针域。
数据域用于存放数据,指针域用于指向下一个节点。
链表的最后一个节点指针域为空(NULL),表示链表的末尾。
常见的链表操作包括创建链表、插入节点、删除节点、遍历链表、查找节点等。
下面我们来看看C语言中常用的链表库函数。
二、常见的C链表库函数1. 创建链表在C语言中,创建链表的函数通常包括初始化链表头节点和链表节点的操作。
```#include <stdio.h>#include <stdlib.h>//定义链表节点typedef struct node {int data;struct node* next;} Node;2. 插入节点插入节点是链表操作中的重要操作,可以在链表的任意位置插入新节点。
常见的插入方式包括头部插入和尾部插入。
```//头部插入节点void insertNodeAtHead(Node* head, int data) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = data;newNode->next = head->next;head->next = newNode;}以上是常见的C链表库函数,这些函数可以帮助我们更方便地操作链表。
在实际开发中,可以根据需要自定义更多的链表操作函数,以满足具体的需求。
c语言递归反转链表

在C语言中,递归反转链表的代码实现相对简洁。
下面是一个实现链表反转的递归函数示例:#include <stdio.h>#include <stdlib.h>// 定义链表节点结构体typedef struct ListNode {int val;struct ListNode *next;} ListNode;// 递归函数,用于反转链表ListNode* reverseList(ListNode* head) {// 递归的基准情况:如果链表为空或者只有一个节点,返回原节点if (head == NULL || head->next == NULL) {return head;}// 递归地反转剩下的链表部分ListNode* newHead = reverseList(head->next);// 将当前节点的next指向null(因为它现在是链表的最后一个节点)head->next->next = head;head->next = NULL;// 返回新的头节点return newHead;}// 辅助函数,用于创建链表ListNode* createList(int[] values, int size) {ListNode* head = NULL;for (int i = size - 1; i >= 0; --i) {ListNode* newNode = malloc(sizeof(ListNode));newNode->val = values[i];newNode->next = head;head = newNode;}return head;}// 打印链表void printList(ListNode* head) {while (head != NULL) {printf("%d ", head->val);head = head->next;}printf("\n");}int main() {int values[] = {1, 2, 3, 4, 5};int size = sizeof(values) / sizeof(values[0]);ListNode* originalHead = createList(values, size);printf("Original list: ");printList(originalHead);ListNode* reversedHead = reverseList(originalHead);printf("Reversed list: ");printList(reversedHead);// 释放链表内存ListNode* current = originalHead;while (current != NULL) {ListNode* temp = current;current = current->next;free(temp);}return 0;}这段代码首先定义了一个链表节点结构体ListNode。
[转载整理]C语言链表实例
![[转载整理]C语言链表实例](https://img.taocdn.com/s3/m/0aca427eb94ae45c3b3567ec102de2bd9605debe.png)
[转载整理]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 }。
c语言双循环的简单例子

c语言双循环的简单例子从代码所示为常见的for语句双重循环,循环原理如下1,对于给二维数组赋值部分,第一次i=0,判断i<3值为真,然后执行二重循环语句,j=0,判断j<2结果为真,因此执行下面的循环体语句,a[0][0]=0+0=0,j++2,第二次循环依旧是在j循环部分执行,j=1,判断j<2结果为真,因此执行下面的循环体语句,a[0][1]=0+1=1,j++3,第三次循环依旧是在j循环部分执行,j=2,判断j<2结果为假,退出j部分循环,i++4,第四次循环,i=1,判断i<3结果为真,然后执行j部分二重循环语句,j=0;判断j<2结果为真,因此执行下面的循环体语句,a[1][0]=1+0=1,j++5,第五次循环,i=1,判断j<2结果为真,执行循环体语句,a[1][1]=1+1=2,j++本文实例讲述了C++双向循环列表用法。
分享给大家供大家参考。
具体如下:1 2 3 4 5 6 7 8 9 1/*双向循环链表*/#include <iostream> using namespace std;1 1 12 13 14 15 16 17 18 19 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 //结构体构造链表的指针域和数据域struct ChainNode{int data; //节点数据ChainNode *left; //节点的前驱指针ChainNode *right; //节点的后继指针};////////////创建n个双向循环链表并返回链表头指针///////// ChainNode* CreateNode(int n){ChainNode *head = NULL; //链表头节点ChainNode *pCur=NULL,*pNew=NULL; //当前节点,新建节点//初始化头结点的前驱和后继节点都为NULLif(n<1) //没有节点返回头节点{return head;}//创建头节点并将器左右指针指向空head = new ChainNode;head->left = NULL;head->right = NULL;2 3 3 3 4 3 5 3 6 3 7 3 8 3 9 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 5 0 5 1 5 2 5head->data = 0;pCur = head;//为防止指针互指带来的混乱,用pCur节点保存了头节点也表示当前指针移动到了头指针//创建n个节点并连接成链表for(int i=0; i<n; i++){pNew = new ChainNode; //创建一个新节点cout<<"请输入数据:";cin>>pNew->data;pCur->right = pNew; //头指针的右指针指向新建节点pNew->left = pCur; //新建节点的左指针执行头节点pNew->right = NULL; //用于最后和头指针进行交换pCur = pNew; //指针往下移动}//最后将头指针的左指针指向最后一个节点,//最后一个节点的有指针指向头指针,构成循环head->left = pCur;pCur->right = head;return head;}5 4 5 5 56 57 58 59 6 0 6 1 6 2 6 3 6 4 6 5 6 6 6 7 6 8 6 9 7 0 7 1 7 2 7 3 7 4 //////////////输出链表头节点///////////////////////void OutList(ChainNode *head) //参数为头指针从头指针开始{cout<<"链表元素输出如下:"<<endl;ChainNode *pCur = head->right;//重第一个节点开始输出//没有指向空节点,则链表没结束输出链表元素while(pCur->right != head){cout<<pCur->data<<" ";pCur = pCur->right;//当前节点指向下一个节点可以遍历链表}cout<<pCur->data<<endl;//输入最后一个元素,它的右指针执行head}///////在双向循环链表后添加n个节点//////ChainNode* AddNode(ChainNode* head, int n){ChainNode *pNew,*pCur;//新添加节点和当前节点5 767 7 78 79 8 0 8 1 8 2 8 3 8 4 8 5 8 6 8 7 8 8 8 9 9 0 9 1 9 2 9 3 9 4 9 5 9pCur = head;//移动到最节点while(pCur->right != head){pCur = pCur->right;//当前节点往下移动一直移到最后一个节点}//新添加n个节点并插入链表for(int i=0; i<n; i++){pNew = new ChainNode;cout<<"输入要添加的节点元素:";cin>>pNew->data;pCur->right = pNew; //头指针的右指针指向新建节点pNew->left = pCur; //新建节点的左指针执行头节点pNew->right = NULL; //用于最后和头指针进行交换pCur = pNew; //指针往下移动}//最后将头指针的左指针指向最后一个节点,//最后一个节点的有指针指向头指针,构成循环head->left = pCur;9 7 9 8 9 9 1 0 0 1 0 1 1 0 2 1 0 3 1 0 4 1 0 5 1 0 6 1 0 7 1 0 8 1 0 9 1 1 0 1 1 1pCur->right = head;return head;}/////在双向循环链表中删除一个节点///////ChainNode* DeleteNode(ChainNode* head, unsigned num) //删除第num个节点{ChainNode *pNew,*pCur,*temp;//新添加节点和当前节点 ,临时交换节点pCur = head;int ncount = 0;//移动到第num-1个节点while(1){ncount++;pCur = pCur->right; //当前节点往下移动if(num == ncount){break; //此时pCur还是指向了第num个节点}}1 2 1 1 3 1 1 4 1 1 5 1 1 6 1 1 7 1 1 8 1 1 9 1 2 0 1 2 1 1 2 2 1 2 3 1 2 4 1 2 5 1//当前节点的前一个节点的右指针指向当前节点的下一个节点//当前节点的下一个节点的左指针指向当前节点的上一个节点构成连接//最后删除当前节点(pCur->left)->right = pCur->right;(pCur->right)->left = pCur->left;delete pCur;return head;}int main(){int num;//创建num个节点并显示cout<<"输入要创建的链表节点个数:";cin>>num;ChainNode *head = CreateNode(num);OutList(head);//往链表后添加n个节点int addnum;cout<<"输入要添加的节点个数:";cin>>addnum;AddNode(head, addnum);6 1 27 1 28 1 29 1 3 0 1 3 1 1 3 2 1 3 3 1 3 4 1 3 5 1 3 6 1 3 7 1 3 8 1 3 9 1 4OutList(head);//删除链表的第del个元素int del;cout<<"输入要删除的第几个位置的节点:"; cin>>del;DeleteNode (head, del);OutList(head);system("pause");return0;}。
双向链表

第8讲 双向链表● 循环单链表的出现,虽然能够实现从任一结点出发沿着链能找到其前趋结点,但时间耗费是O (n) 。
● 如果希望从表中快速确定某一个结点的前趋,另一个解决方法就是在单链表的每个结点里再增加一个指向其前趋的指针域prior 。
这样形成的链表中就有两条方向不同的链,我们称之为双向链表。
● 双向链表的结构定义如下:typedef struct DNode{ ElemType data ;struct DNode *prior ,*next ;}DNode, * DoubleList ;● 双向链表的结点结构如图所示。
图:双链表的结点结构注:● 双向链表也是由头指针唯一确定的,● 增加头结点能使双链表的某些运算变得方便● 由于在双向链表中既有前向链又有后向链,寻找任一个结点的直接前驱结点与直接后继结点变得非常方便。
● 设指针p 指向双链表中某一结点,则有下式成立:p->prior->next = p = p->next->prior●在双向链表中,那些只涉及后继指针的算法,如求表长度、取元素、元素定位等,与单链表中相应的算法相同,● 但对于前插和删除操作则涉及到前驱和后继两个方向的指针变化,因此与单链表中的算法不同。
1、 双向链表的前插操作【算法思想】欲在双向链表第i 个结点之前插入一个的新的结点,则指针的变化情况如图所示:… p …s->prior=p->prior; ①p->prior->next=s;②s->next=p; ③p->prior=s;④【算法描述】int DlinkIns(DoubleList L,int i,ElemType e){DNode *s,*p;… /*先检查待插入的位置i是否合法(实现方法同单链表的前插操作)*/… /*若位置i合法,则找到第i个结点并让指针p指向它*/s=(DNode*)malloc(sizeof(DNode));if (s){ s->data=e;s->prior=p->prior; ①p->prior->next=s; ②s->next=p; ③p->prior=s; ④r eturn TRUE;}else return FALSE;}2、双向链表的删除操作【算法思想】欲删除双向链表中的第i个结点,则指针的变化情况如图所示:p->prior->next=p->next; ①p->next->prior=p->prior; ②free(p);【算法描述】int DlinkDel(DoubleList L,int i,ElemType *e){DNode *p;… /*先检查待插入的位置i 是否合法(实现方法同单链表的删除操作)*/… /*若位置i 合法,则找到第i 个结点并让指针p 指向它*/*e=p->data;p->prior->next=p->next; ①p->next->prior=p->prior; ②free(p);return TRUE;}3、 双向循环链表双向链表可以有循环表,称为双向循环链表。
c语言中linklist的作用

c语言中linklist的作用C语言中LinkList的作用什么是LinkListLinkList(链表)是C语言中用来存储和操作数据的一种数据结构。
它与数组相比,拥有更灵活的插入和删除操作。
链表由节点(Node)组成,每个节点包含一个数据项和一个指向下一个节点的指针。
链表的头节点是链表的起始点,尾节点则指向NULL。
LinkList的作用1.动态内存分配:链表的节点可以动态地分配和释放内存,因此链表可以根据实际需要进行动态的添加和删除操作,不受固定大小的限制。
2.插入和删除操作效率高:由于链表的特性,插入和删除操作只需要修改节点指针的指向,而不需要移动其他节点,因此链表在某些特定场景下可以比数组更高效。
3.实现高级数据结构:链表可以用来实现其他高级数据结构,比如栈(Stack)和队列(Queue),或者作为其他数据结构的底层实现。
4.提供灵活的数据结构设计:链表可以设计成单向链表、双向链表或循环链表,根据实际需求选择合适的链表结构。
LinkList的应用场景链表在许多编程问题中都有着广泛的应用,以下是一些常见的应用场景: - 线性表:链表可以实现线性表,可以用来存储和操作一组有序的数据。
- 多项式运算:链表可以用来存储和运算多项式,实现多项式的相加、相乘等操作。
- 图的表示:链表可以用来表示图的连接关系,比如邻接链表表示法。
- 高级数据结构:链表可以作为实现其他高级数据结构的基础,比如树(Tree)、图(Graph)等。
- 文件操作:链表可以用来实现文件的读取和写入操作,链表可以实现文件的增删改查等功能。
总结链表作为一种灵活和高效的数据结构,广泛应用于C语言的编程中。
通过链表,我们可以动态地分配内存,高效地进行插入和删除操作。
而且,链表还可以作为其他高级数据结构的基础实现,扩展了数据结构的功能和应用场景。
在C语言中,掌握链表的使用方法和原理,对于编写高效的程序和解决复杂的编程问题都有很大的帮助。
数据结构中的双向链表实现和应用场景

数据结构中的双向链表实现和应用场景双向链表是一种常用的数据结构,它在许多实际应用中都发挥着重要的作用。
本文将介绍双向链表的实现原理以及一些常见的应用场景。
一、双向链表的实现原理双向链表由一系列节点组成,每个节点包含两个指针,一个指向前一个节点,一个指向后一个节点。
相比于单向链表,双向链表可以实现双向遍历,提高了一些操作的效率。
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指针指向后一个节点。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配内存空间!");
exit(0);
}
p->rlink=s;
printf("请输入第%d个人的姓名",i+1);
scanf("%s",s->name);
s->llink=p;
s->rlink=NULL;
p=h;
for(i=0;i<n;i++)
{
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配内存空间!");
exit(0);
}
p->rlink=s;
printf("请输入第%d个人的姓名",i+1);
scanf("%s",s->name);
1、在建立一个循环链表时,必须使其最后一个结点的指针指向表头结点,而不是象单链表那样置为NULபைடு நூலகம்。此种情况还使用于在最后一个结点后插入一个新的结点。
2、在判断是否到表尾时,是判断该结点链域的值是否是表头结点,当链域值等于表头指针时,说明已到表尾。而非象单链表那样判断链域值是否为NULL。
二、双向链表
searchpoint=search(head,studname);
printf("你所要查找的人的姓名是:%s",*&searchpoint->name);
}
2、插入
对于双向循环链表,我们现在可以随意地在某已知结点p前或者p后插入一个新的结点。
假若s,p,q是连续三个结点的指针,若我们要在p前插入一个新结点r,则只需把s的右链域指针指向r,r的左链域指针指向s,r的右链域指针指向p,p的左链域指针指向r即可。
}
printf("没有查找到该数据!");
}
void print(stud *h)
{
int n;
stud *p;
p=h->rlink;
printf("数据信息为:\n");
while(p!=h)
{
printf("%s ",&*(p->name));
p=p->rlink;
}
printf("\n");
}
下例就是应用双向循环链表查找算法的一个程序。
#include<stdio.h>
#include<malloc.h>
#define N 10
typedef struct node
{
char name[20];
struct node *llink,*rlink;
}stud;
stud * creat(int n)
在双向链表中,结点除含有数据域外,还有两个链域,一个存储直接后继结点地址,一般称之为右链域;一个存储直接前驱结点地址,一般称之为左链域。在C语言中双向链表结点类型可以定义为:
typedef struct node
{
int data; /*数据域*/
struct node *llink,*rlink; /*链域,*llink是左链域指针,*rlink是右链域指针*/
s->llink=p;
s->rlink=NULL;
p=s;
}
h->llink=s;
p->rlink=h;
return(h);
}
stud * search(stud *h,char *x)
}JD;
当然,也可以把一个双向链表构建成一个双向循环链表。
双向链表与单向链表一样,也有三种基本运算:查找、插入和删除。
双向链表的基本运算:
1、查找
假若我们要在一个带表头的双向循环链表中查找数据域为一特定值的某个结点时,我们同样从表头结点往后依次比较各结点数据域的值,若正是该特定值,则返回指向结点的指针,否则继续往后查,直到表尾。
main()
{
int number;
char studname[20];
stud *head,*searchpoint;
number=N;
clrscr();
head=creat(number);
print(head);
printf("请输入你要查找的人的姓名:");
scanf("%s",studname);
在p,q之间插入原理也一样。
下面就是一个应用双向循环链表插入算法的例子:
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define N 10
typedef struct node
{
char name[20];
struct node *llink,*rlink;
p=s;
}
h->llink=s;
p->rlink=h;
return(h);
}
stud * search(stud *h,char *x)
{
stud *p;
char *y;
p=h->rlink;
while(p!=h)
{
y=p->name;
if(strcmp(y,x)==0)
return(p);
else p=p->rlink;
双向链表其实是单链表的改进。
当我们对单链表进行操作时,有时你要对某个结点的直接前驱进行操作时,又必须从表头开始查找。这是由单链表结点的结构所限制的。因为单链表每个结点只有一个存储直接后继结点地址的链域,那么能不能定义一个既有存储直接后继结点地址的链域,又有存储直接前驱结点地址的链域的这样一个双链域结点结构呢?这就是双向链表。
}stud;
stud * creat(int n)
{
stud *p,*h,*s;
int i;
if((h=(stud *)malloc(sizeof(stud)))==NULL)
{
printf("不能分配内存空间!");
exit(0);
}
h->name[0]=’\0’;
h->llink=NULL;
h->rlink=NULL;
链表的C语言实现之循环链表及双向链表
作者:未知文章出处:编程中国更新时间:2007-10-9
一、循环链表
循环链表是与单链表一样,是一种链式的存储结构,所不同的是,循环链表的最后一个结点的指针是指向该循环链表的第一个结点或者表头结点,从而构成一个环形的链。
循环链表的运算与单链表的运算基本一致。所不同的有以下几点:
{
stud *p,*h,*s;
int i;
if((h=(stud *)malloc(sizeof(stud)))==NULL)
{
printf("不能分配内存空间!");
exit(0);
}
h->name[0]=’\0’;
h->llink=NULL;
h->rlink=NULL;
p=h;
for(i=0;i<n;i++)