数据结构之双向带头节点带环链表的实现
2018-04-03 13:51
519 查看
之前我们曾实现过单向不带头结点不带环的单链表,但是发现,在运用中并不是那么的好用,因为单向链表每个元素只能找到他后面的元素,而无法对其前面进行查找,这样在实际的使用中并不好用,而双向带头结点带环链表却是非常好用,因为他有两个指针,一个可以查找到后面的元素,同样另一个也可以查到前面的元素。
其实所谓双向链表,即两个指针next与prev一个指针可以向后进行遍历,一个指针可以向前,而头结点就相当于一个傀儡节点,它里面的数据并不具有什么意义,而它的作用就是一个链表的头部,所以说当一个双链表创建完毕以后,它的头结点是不能再改变的。而且双向链表的各个操作都是利用了两个指针之间的关系直接建立并不需要太多的套路等,所以后面不再赘述,直接实现。
接着在我们实现基本操作之前,同样我们应该先定义一个双链表的节点,此节点中应包括数据、前指针、后指针三个元素。
接着,我们在这里罗列一下我们将要实现的操作:
以上就是基本的实现操作,接下来是对代码的测试。
欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!
其实所谓双向链表,即两个指针next与prev一个指针可以向后进行遍历,一个指针可以向前,而头结点就相当于一个傀儡节点,它里面的数据并不具有什么意义,而它的作用就是一个链表的头部,所以说当一个双链表创建完毕以后,它的头结点是不能再改变的。而且双向链表的各个操作都是利用了两个指针之间的关系直接建立并不需要太多的套路等,所以后面不再赘述,直接实现。
接着在我们实现基本操作之前,同样我们应该先定义一个双链表的节点,此节点中应包括数据、前指针、后指针三个元素。
typedef struct DbLinkNode{ DbLinkType data;//数据 struct DbLinkNode* prev;//前指针 struct DbLinkNode* next;//后指针 }DbLinkNode;
接着,我们在这里罗列一下我们将要实现的操作:
DbLinkNode* DbCreat(DbLinkType value);//创建新的双链表节点 void DbLinkInit(DbLinkNode** phead);//初始化双链表 void DbLinkPrint(DbLinkNode* head);//打印双链表 void DbLinkPushBack(DbLinkNode* head, DbLinkType value);//尾部插入 void DbLinkPushFront(DbLinkNode* head, DbLinkType value);//头部插入 void DbLinkPopBack(DbLinkNode* head);//尾部删除 void DbLinkPopFront(DbLinkNode* head);//头部删除 DbLinkNode* DbLinkFind(DbLinkNode* head, DbLinkType to_find);//查找某个元素 void DbLinkInsert(DbLinkNode* pos, DbLinkType value);//在pos位置之前插入一个元素 void DbLinkInsertAfter(DbLinkNode* pos,DbLinkType value);//在pos位置之后插入一个元素 void DbLinkErase(DbLinkNode* head,DbLinkNode* pos);//删除pos位置元素 void DbLinkRemove(DbLinkNode* head,DbLinkType to_delete);//删除双链表元素,只删除第一次出现的 void DbLinkRemoveAll(DbLinkNode* head,DbLinkType to_delete);//删除链表中所有to_delete size_t DbLinkSize(DbLinkNode* head);//计算链表大小 int DbLinkEmpty(DbLinkNode* head);//判断链表是否为空
打印、初始化、创建新节点
要对链表进行操作,最基本的初始化、创建新节点、打印这三个步骤必须要有。所以从这个开始。void DbLinkPrint(DbLinkNode* head)//打印双链表 { if(head == NULL) { return;//非法输入 } DbLinkNode* cur = head->next; while(cur != head) { printf("[%c|%p]",cur->data,cur); cur = cur->next; } printf("\n"); cur = head->prev; while(cur != head) { printf("[%c|%p]",cur->data,cur); cur = cur->prev; } printf("\n"); printf("\n"); printf("\n"); return; } DbLinkNode* DbCreat(DbLinkType value)//创建新的双链表节点 { DbLinkNode* new_node = (DbLinkNode*)malloc(sizeof(DbLinkNode)); new_node->next = new_node; new_node->prev = new_node; new_node->data = value; return new_node; } void DbLinkInit(DbLinkNode** phead)//初始化双链表 { if(phead == NULL) { return;//非法输入 } *phead = DbCreat(0); }
尾插、头插、尾删、头删
void DbLinkPushBack(DbLinkNode* head, DbLinkType value)//尾部插入 { if(head == NULL) { return;//非法输入 } DbLinkNode* new_node = DbCreat(value); DbLinkNode* pre = head->prev; pre->next = new_node; new_node->prev = pre; head->prev = new_node; new_node->next = head; return; } void DbLinkPushFront(DbLinkNode* head, DbLinkType value)//头部插入 { if(head == NULL) { return;//非法输入 } DbLinkNode* new_node = DbCreat(value); DbLinkNode* tmp = head->next; new_node->next = tmp; tmp->prev = new_node; head->next = new_node; new_node->prev = head; return; } void DbLinkPopBack(DbLinkNode* head)//尾部删除 { if(head == NULL) { return; } if(head->next == head) { return; } DbLinkNode* to_delete = head->prev; to_delete->prev->next = head; head->prev = to_delete->prev; free(to_delete); return; } void DbLinkPopFront(DbLinkNode* head)//头部删除 { if(head == NULL) { return; } if(head->next == head) { return; } DbLinkNode* to_delete = head->next; DbLinkNode* pre = to_delete->next; head->next = pre; pre->prev = head; free(to_delete); return; }
查找元素
DbLinkNode* DbLinkFind(DbLinkNode* head, DbLinkType to_find)//查找某个元素 { if(head == NULL) { return NULL;//非法输入 } DbLinkNode* cur = head->next; while(cur != head) { if(cur->data == to_find) { return cur; } cur = cur->next; } return NULL; }
在pos位置之前插入,在pos位置之后插入
void DbLinkInsert(DbLinkNode* pos, DbLinkType value)//在pos位置之前插入一个元素 { if(pos == NULL) { return; } DbLinkNode* new_node = DbCreat(value); DbLinkNode* tmp = pos->prev; tmp->next = new_node; new_node->prev = tmp; new_node->next = pos; pos->prev = new_node; return; } void DbLinkInsertAfter(DbLinkNode* pos,DbLinkType value)//在pos位置之后插入一个元素 { if(pos == NULL) { return;//非法输入 } DbLinkNode* new_node = DbCreat(value); DbLinkNode* tmp = pos->next; tmp->prev = new_node; new_node->next = tmp; pos->next = new_node; new_node->prev = pos; return; }
删除pos位置元素
void DbLinkErase(DbLinkNode* head,DbLinkNode* pos)//删除pos位置元素 { if(head == NULL || pos == NULL) { return;//非法输入 } if(head->next == head) { return;//空链表 } DbLinkNode* pos_next = pos->next; DbLinkNode* pos_prev = pos->prev; pos_next->prev = pos_prev; pos_prev->next = pos_next; free(pos); return; }
删除双链表中value元素只删除第一个/删除所有
void DbLinkRemove(DbLinkNode* head,DbLinkType to_delete)//删除双链表元素,只删除第一次出现的 { if(head == NULL) { return; } if(head->next == head) { return; } DbLinkNode* cur = head->next; while(cur != head) { if(cur->data == to_delete) { DbLinkErase(head,cur); return; } cur = cur->next; } return; } void DbLinkRemoveAll(DbLinkNode* head,DbLinkType to_delete)//删除链表中所有to_delete { if(head == NULL) { return; } if(head->next == head) { return; } while(1) { DbLinkNode* pos_delete = DbLinkFind(head,to_delete); if(pos_delete == NULL) { return; } DbLinkErase(head,pos_delete); } }
计算链表大小、判断链表是否为空(为空返回0,不为空返回1)
size_t DbLinkSize(DbLinkNode* head)//计算链表大小 { if(head == NULL) { return -1; } size_t size = 0; DbLinkNode* cur = head->next; while(cur != head) { size++; cur = cur->next; } return size; } int DbLinkEmpty(DbLinkNode* head)//判断链表是否为空 { if(head == NULL) { return -1; } return head->next==head?0:1; }
以上就是基本的实现操作,接下来是对代码的测试。
void TestPushBack() { HEAD; DbLinkNode* head; DbLinkInit(&head); DbLinkPushBack(head,'a'); DbLinkPushBack(head,'b'); DbLinkPushBack(head,'c'); DbLinkPushBack(head,'d'); DbLinkPrint(head); } void TestPushFront() { HEAD; DbLinkNode* head; DbLinkInit(&head); DbLinkPushFront(head,'a'); DbLinkPushFront(head,'b'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'d'); DbLinkPrint(head); } void TestPopBack() { HEAD; DbLinkNode* head; DbLinkInit(&head); DbLinkPushFront(head,'a'); DbLinkPushFront(head,'b'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'d'); DbLinkPrint(head); DbLinkPopBack(head); DbLinkPrint(head); } void TestPopFront() { HEAD; DbLinkNode* head; DbLinkInit(&head); DbLinkPushFront(head,'a'); DbLinkPushFront(head,'b'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'d'); DbLinkPrint(head); DbLinkPopFront(head); DbLinkPrint(head); } void TestFind() { HEAD; DbLinkNode* head; DbLinkInit(&head); DbLinkPushFront(head,'a'); DbLinkPushFront(head,'b'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'d'); DbLinkNode* ret = DbLinkFind(head,'b'); printf("[%c|%p]\n",ret->data,ret); ret = DbLinkFind(head,'z'); printf("%p\n",ret); } void TestInsert() { HEAD; DbLinkNode* head; DbLinkInit(&head); DbLinkPushFront(head,'a'); DbLinkPushFront(head,'b'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'d'); DbLinkPrint(head); DbLinkNode* pos_b = DbLinkFind(head,'b'); DbLinkInsert(pos_b,'z'); DbLinkPrint(head); } void TestInsertAfter() { HEAD; DbLinkNode* head; DbLinkInit(&head); DbLinkPushFront(head,'a'); DbLinkPushFront(head,'b'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'d'); DbLinkPrint(head); DbLinkNode* pos_b = DbLinkFind(head,'b'); DbLinkInsertAfter(pos_b,'z'); DbLinkPrint(head); } void TestErase() { HEAD; DbLinkNode* head; DbLinkInit(&head); DbLinkPushFront(head,'a'); DbLinkPushFront(head,'b'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'d'); DbLinkPrint(head); DbLinkNode* pos_b = DbLinkFind(head,'b'); DbLinkErase(head,pos_b); DbLinkPrint(head); } void TestRemove() { HEAD; DbLinkNode* head; DbLinkInit(&head); DbLinkPushFront(head,'a'); DbLinkPushFront(head,'b'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'d'); DbLinkPrint(head); DbLinkRemove(head,'c'); DbLinkPrint(head); } void TestRemoveAll() { HEAD; DbLinkNode* head; DbLinkInit(&head); DbLinkPushFront(head,'a'); DbLinkPushFront(head,'b'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'d'); DbLinkPrint(head); DbLinkRemoveAll(head,'c'); DbLinkPrint(head); } void TestSize() { HEAD; DbLinkNode* head; DbLinkInit(&head); DbLinkPushFront(head,'a'); DbLinkPushFront(head,'b'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'c'); DbLinkPrint(head); size_t sz = DbLinkSize(head); printf("%lu\n",sz); } void TestEmpty() { HEAD; DbLinkNode* head; DbLinkInit(&head); int n = DbLinkEmpty(head); printf("%d\n",n); DbLinkPushFront(head,'a'); DbLinkPushFront(head,'b'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'c'); DbLinkPushFront(head,'c'); DbLinkPrint(head); n = DbLinkEmpty(head); printf("%d\n",n); } int main() { TestPushBack(); TestPushFront(); TestPopBack(); TestPopFront(); TestFind(); TestInsert(); TestInsertAfter(); TestErase(); TestRemove(); TestRemoveAll(); TestSize(); TestEmpty(); printf("\n"); printf("\n"); printf("\n"); printf("\n"); return 0; }
欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!
相关文章推荐
- C实现带头节点带环双向链表的操作
- 数据结构示例之带头节点的双向循环链表
- 带头节点带环的双向循环链表
- 【c++版数据结构】之用带头节点的单链表实现一元多项式(C语言版)
- 带头节点、带环的双向链表的一些基本操作
- 【C++】模板实现带头节点的双向循环链表
- c实现按访问频度非递增有序的带头节点的双向链表检索关键字
- !-- 带头结点带环的双向链表的相关操作实现 --!
- 数据结构示例之带头节点的双向循环链表
- C语言实现双向非循环链表(带头结点尾结点)的节点插入
- 数据结构-带头结点带环的双向链表基本操作
- 带头带环双向链表的实现及其相关操作。。
- 数据结构-java与c实现带头结点的单链表
- 容器第四课,JDK源代码分析,自己实现LinkedList,双向链表的概念_节点定义
- 数据结构--java实现双向链表
- 【c++版数据结构】之循环双链表的实现(带头结点以及尾节点)
- 基础数据结构--双向链表的实现
- 数据结构:带头结点的双向循环链表
- 数据结构之C++实现无头节点链表(List)(无主函数)
- 数据结构学习之链表(单向、单循环以及双向)(递归实现)