双向链表的基本操作

1.双向链表的数据结构
typedef char DLinkType;typedef struct DLinkNode 
{ DLinkType data; struct DLinkNode* next; struct DLinkNode* prev; 
}DLinkNode; 

    双向带头结点的链表有三个成员, 一个是数据, 一个是指针 next 指向当前结点的下一个结点, 一个指针 prev 指向当前结点的 前一个结点,即每一个节点都有一个直接的前驱, 一个直接的后继, 这里只讨论带头结点的双向链表。

2.双向链表的初始化
/*** 初始化双链表**/void DLinkListInit(DLinkNode** phead)
{if(phead == NULL){return;//非法输入}*phead = (DLinkNode*)malloc(sizeof(DLinkNode));(*phead) -> data = 0;(*phead) -> next = *phead;(*phead) -> prev = *phead;
}

    带头结点双向链表的初始化即就是用一个傀儡节点代表其为空,这里将头节点的数据初始化为 0, 注意,双向链表中没有空指针,所以将双向链表的头节点的 next 指向它自己, 将双向链表的 prev 指向它自己,即判断一个双向带头节点的链表是否为空的条件就是head -> next == head 或者是 head -> prev == head。

3.创建一个新节点

    既然需要对链表进行插入数据, 那便需要对其创建一个指定数据的节点,然后将其插入到当前的链表中。创建一个节点就是对其先分配空间, 再将节点对应的数据改为需要的目标数据。

/*** 创建一个新节点**/
DLinkNode* DLinkNodeCreat(DLinkType value)
{DLinkNode* new_node = (DLinkNode*)malloc(sizeof(DLinkNode));if(new_node == NULL){return NULL;//内存分配失败}new_node -> data = value;new_node -> next = new_node;new_node -> prev = new_node;return new_node;
}
4.头插一个新结点

 &enap; &enap;对双向链表的头插节点也就是先创建一个新结点,然后定义一个指针 prev 指向头结点的下一个节点, 即prev = head -> next, 然后修改对应的 prev 和 所创建的新结点 new_node 的指向, 即 让 prev -> next = new_node, 再让new_node -> prev = prev,就OK了

/*** 头插一个节点**/void DLinkListPushFront(DLinkNode* head, DLinkType value)
{if(head == NULL){return;//非法输入}DLinkNode* new_node = DLinkNodeCreat(value);DLinkNode* prev = head;DLinkNode* next = head -> next;prev -> next = new_node;new_node -> prev = prev;new_node -> next = next;next -> prev = new_node;
}
5.头删一个节点

     既然头删一个节点就必须先定义一个指针 to_delete 指向要删除的节点, 即 head ->next, 然后在定义一个指针指向要删除的元素的下一个节点, 即定义一个指针 next = to_delete -> next, 然后修改head和 next 指针的指向即可, 最后将 to_delete 所指向的节点销毁即可。

/*** 头删一个节点**/
void DLinkListPopFront(DLinkNode* head)
{if(head == NULL){return;//非法输入}if(head -> next == head){return;//空链表}DLinkNode* to_delete = head -> next;DLinkNode* next = to_delete -> next;head -> next = next;next -> prev = head;DLinkNodeDstroy(to_delete);
}/*** 销毁一个节点**/void DLinkNodeDstroy(DLinkNode* to_delete)
{free(to_delete);to_delete = NULL;
}
6.尾插一个节点

    尾插一个节点和链表头插一个元素道理基本相似, 即先创建一个节点 new_node, 然后在定义一个指针 prev = head -> prev,最后修改 head 和 new_node 指针的指向, 接下来再修改 new_node 和 next 指针的指向就可以了。即让 head -> prev = new_node, new_node -> next = head, new_node -> prev = prev, prev -> next = new_node, 此时就已经将新的元素尾插到链表中了

/*** 尾插一个节点**/DLinkNode* DLinkListPushBack(DLinkNode* head, DLinkType value)
{if(head == NULL){return NULL;//非法输入}DLinkNode* new_node = DLinkNodeCreat(value);DLinkNode* next = head -> next;new_node -> next = next;next -> prev = new_node;head -> next = new_node;new_node -> prev = head;return head;
}
7.尾删一个节点

    往双链表中尾插一个元素就是先找到最后一个节点, to_delete = head -> prev, 然后记下 to_delete 节点的前一个节点, 即 prev = to_delete -> prev, 然后让 prev -> next = head, haed -> prev = prev, 再将to_delete 删除就可以了

/*** 尾删一个元素**/void DLinkListPopBack(DLinkNode* head)
{if(head == NULL){return;//非法输入}if(head -> next == head){return;//删除空链表}DLinkNode* to_delete = head -> prev;DLinkNode* prev = to_delete -> prev;head -> prev = prev;prev -> next = head;DLinkNodeDstroy(to_delete);
}
8.在双向链表中查找值为 to_find 节点,并且返回该节点所对应的位置

 &esnp;  定义一个指针cur 指向 head -> next, 然后让 cur 依次遍历整个链表, 当 cur -> data == to_find 时,就将此时的 cur 返回即可


DLinkNode* DLinkListFind(DLinkNode* head, DLinkType to_find)
{if(head == NULL){return NULL;//非法输入}if(head -> next == head){return NULL;}DLinkNode* cur = head -> next;for(; cur != head; cur = cur -> next){if(cur -> data == to_find){return cur;}}return NULL;//没有找到
}
9.往对应位置 pos 处插入一个值为 value的新结点

    往指定位置插入一个值为value 的节点, 需要先创建一个新结点, 然后定义一个指针 prev = pos -> prev, 再定义一个指针 next = pos -> next, 然后改变 prev 和 新节点 之间指针的指向, 以及 新结点和next指针之间的指向就可以将其插入到指定位置 pos 处了

/*** 往 pos 所对应的位置处插入 value ***/void DLinkListInsert(DLinkNode* pos, DLinkType value)
{if(pos == NULL){return;//非法输入}DLinkNode* new_node = DLinkNodeCreat(value);DLinkNode* prev = pos -> prev;//prev vs new_nodeprev -> next = new_node;new_node -> prev = prev;//new_node vs posnew_node -> next = pos;pos -> prev = new_node;
}
10.往指定位置之后插入一个值为 value 的结点

     先创建一个新结点 new_node,再定义一个指针 prev = pos, 接下来定义一个指针 next = pos -> next, 然后改变 new_node 节点和 prev 节点 之间的指向, 最后改变 new_node 和 next 之间节点指针指向就 OK 了

/*** 往指定位置之后插入一个元素**/void DLinkListInsertAfter(DLinkNode* pos, DLinkType value)
{if(pos == NULL){return;//非法输入}DLinkNode* new_node = DLinkNodeCreat(value);DLinkNode* next = pos -> next;pos -> next = new_node;new_node -> prev = pos;new_node -> next = next;next -> prev = new_node;
}
11. 删除某个元素对应的结点

    删除某个元素对应的节点就先找到要删除节点对应的位置, 然后再将这个位置对应的节点删掉就可以了, 如果链表中没有这个元素,或者链表是空链表则直接返回.

/*** 删除某个元素对应的结点**/void DLinkListErase(DLinkNode* head, DLinkType to_delete)
{if(head == NULL){return;//非法输入}if(head -> next == NULL){return;//删除空链表}DLinkNode* cur = DLinkListFind(head, to_delete);if(cur == NULL){return;//删除不存在的节点}DLinkNode* prev = cur -> prev;DLinkNode* next = cur -> next;prev -> next = next;next -> prev = prev;DLinkNodeDstroy(cur);
}
12.求链表长度
/*** 求链表长度**/size_t DLinkListSize(DLinkNode* head)
{DLinkNode* cur = head -> next;size_t size = 0;while(cur != head){cur = cur -> next;size++;}return size;
}
13. 链表判空
/*** 链表判空**/int DLinkListEmpty(DLinkNode* head)
{if(head == NULL){return -1;//非法输入}if(head -> next == head){return 1;}return 0;
}
14.删除链表中所有相同的结点

void DLinkListRemoveAll(DLinkNode* head, DLinkType to_delete)
{if(head == NULL){                                                                                                                                                    return;//非法输入}if(head -> next == head){return;//空链表}DLinkNode* cur = head -> next;while(cur != head){if(to_delete == cur -> data){DLinkListErase(head, to_delete);}cur = cur -> next;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384091.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

匿名管道

1.进程通信的目的 (1) 数据传输: 一个进程需要将它的数据传输给另一个进程     (2) 资源共享: 多个进程之间共享同样的资源     (3) 通知事件: 一个进程需要向另一个或一组进程发送消息, 通知它们发生了什么事情 2.管道 管道是一种进程之间通信的一种方式, 我们把从…

Currency Exchange——最短路Bellman-Ford算法

【题目描述】 Several currency exchange points are working in our city. Let us suppose that each point specializes in two particular currencies and performs exchange operations only with these currencies. There can be several points specializing in the sam…

C++实现String类

http://blog.csdn.net/randyjiawenjie/article/details/6709539 C实现String类,还没有完成,待继续。 有以下注意的点: (1)赋值操作符返回的是一个MyString&,而重载的返回的是一个MyString。其中的原因…

POJ 3370 Halloween treats——鸽巢原理+思维

【题目描述】 POJ 3370 Halloween treats Description Every year there is the same problem at Halloween: Each neighbour is only willing to give a certain total number of sweets on that day, no matter how many children call on him, so it may happen that a chi…

将信号量代码生成静态库以及动态库

1.信号量相关代码生成静态库 2.信号量相关代码生成动态库

Wormholes——Bellman-Ford判断负环

【题目描述】 While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of…

C++11 标准新特性:Defaulted 和 Deleted 函数

https://www.ibm.com/developerworks/cn/aix/library/1212_lufang_c11new/index.html Defaulted 函数 背景问题 C 的类有四类特殊成员函数,它们分别是:默认构造函数、析构函数、拷贝构造函数以及拷贝赋值运算符。这些类的特殊成员函数负责创建、初始化、…

顺序表实现栈相关操作

1.栈的相关概念 栈是一种特殊的线性表, 其中只允许在固定的一端进行插入和删除元素.进行数据插入和删除的一端叫做栈顶, 另一端成为栈底. 不含任何元素的栈称为空栈, 栈又称为先进先出的线性表. 2. 顺序栈的结构 3. 顺序栈的具体操作 (1). 数据结构 typedef char SeqStackTyp…

MPI Maelstrom——Dijkstra

【题目描述】 BIT has recently taken delivery of their new supercomputer, a 32 processor Apollo Odyssey distributed shared memory machine with a hierarchical communication subsystem. Valentine McKee’s research advisor, Jack Swigert, has asked her to bench…

双向带环带头结点的链表实现栈

1. 数据结构 利用带头结点带环的结点实现栈的相关操作.因此, 每一个结点包括了一个前驱, 一个后继, 还有一个数据成员 typedef char DLinkStackType;typedef struct DLinkStack {DLinkStackType data;struct DLinkStack* next;struct DLinkStack* prev; }DLinkStack;2. 初始化…

Cow Contest——Floyed+连通性判断

【题目描述】 N (1 ≤ N ≤ 100) cows, conveniently numbered 1…N, are participating in a programming contest. As we all know, some cows code better than others. Each cow has a certain constant skill rating that is unique among the competitors. The contest …

C++11 标准新特性:委派构造函数

https://www.ibm.com/developerworks/cn/rational/1508_chenjing_c11/index.html陈 晶2015 年 8 月 11 日发布WeiboGoogle用电子邮件发送本页面 1本文首先介绍了在委派构造函数提出之前类成员构造所面临的问题,再结合实例介绍了委派构造函数的用法,并说明…

顺序表实现队列

一. 队列相关概念 队列是只允许在一段进行插入元素, 在另一端进行删除元素的线性表,即只允许对队列进行尾插,头删的操作.队列具有先进先出, 后进后出的特性.          1.初始化 void SeqQueInit(SeqQue* q) {if(q NULL){return;//非法输入}q -> head 0;q -> …

Arbitrage——判断正环Bellman-Ford/SPFA

【题目描述】 Arbitrage is the use of discrepancies in currency exchange rates to transform one unit of a currency into more than one unit of the same currency. For example, suppose that 1 US Dollar buys 0.5 British pound, 1 British pound buys 10.0 French …

链表实现队列

上篇博客是用顺序表实现队列, 现在用双向带头结点带环链表实现对队列的出队列, 入队列, 取队首元素, 以及销毁队列的相关操作 1.初始化链表 void DLinkQueInit(DLinkQue** q) {if(q NULL){return;//非法输入}if(*q NULL){return;//非法输入带头结点的链表至少有一个傀儡结点…

HDU - 1796——容斥原理+二进制枚举

【题目描述】 Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that they can divided exactly by any integers in the set. For example, N12, and M-integer set is {2,3}, so there is another set {2,3,4,…

数据结构学习(二)——单链表的操作之头插法和尾插法创建链表

http://blog.csdn.net/abclixu123/article/details/8210109 链表也是线性表的一种,与顺序表不同的是,它在内存中不是连续存放的。在C语言中,链表是通过指针相关实现的。而单链表是链表的其中一种,关于单链表就是其节点中有数据域和…

信号的基本概念以及信号的产生

一. 信号产生的场景 1. 用户输入命令, 在shell 启动一个前台进程      2. 当用户按一下 Ctrl C 的时候,从键盘产生一个硬件中断      3. 此时CPU 正在执行这个进程的带代码, 则该进程的执行代码暂停执行, CPU 从用户态切换到内核态处理该硬件中断.      4. 中断…

HDU - 1028——母函数入门

【题目描述】 “Well, it seems the first problem is too easy. I will let you know how foolish you are later.” feng5166 says. “The second problem is, given an positive integer N, we define an equation like this: Na[1]a[2]a[3]…a[m]; a[i]>0,1<m<N;…

信号的阻塞

一. 阻塞信号 1.信号的相关概念     (1) 递达: 实际执行信号的处理动作称为信号的递达     (2) 未决: 信号从产生到递达之间的过程叫做信号的未决     (3) 阻塞: 进程可以选择阻塞某个信号, 被阻塞的信号产生时将保持在未决状态, 直到进程解除该信号的屏蔽, 才…