双向链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,双向链表比起单链表有天生的优势
不熟悉单链表的同学们可以参考这篇文章(链表及相关函数实现),看完之后在和双向链表的操作进行对比,高下立见
DLinklist.c
#pragma once
// 双向带环链表
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
typedef char Datatype;
typedef struct DLinkNode {
Datatype data;
struct DLinkNode* prev;
struct DLinkNode* next;
}DLinkNode;
// 初始化双链表
void DLinklistInit(DLinkNode** phead);
// 双链表头插
void DLinklistPushfront(DLinkNode* head, Datatype value);
// 双链表尾插
void DLinklistPushback(DLinkNode* head, Datatype value);
// 双链表头删
void DLinklistPopfront(DLinkNode* head);
// 双链表尾删
void DLinklistPopback(DLinkNode* head);
// 双链表中查找一个元素,返回节点的地址
DLinkNode* DlinklistFind(DLinkNode* head, Datatype to_find);
// 在指定元素位置之前插入元素
void DLinklistInsert(DLinkNode* head, DLinkNode* pos, Datatype value);
// 在指定元素位置之后插入元素
void DLinklistInsertAfter(DLinkNode* head, DLinkNode* pos, Datatype value);
// 删除指定位置元素
void DLinklistErase(DLinkNode* head, DLinkNode* pos);
// 删除指定元素
void DLinklistRemove(DLinkNode* head, Datatype value);
// 删除制定所有元素
void DLinklistRemoveAll(DLinkNode* head, Datatype value);
// 求双向表长度
size_t DLinklistSize(DLinkNode* head);
// 双向表是否为空
int DLinklistEmpty(DLinkNode* head);
DLinklist.c
#include "main.h"
//创建节点
DLinkNode* Creat(Datatype value) {
DLinkNode* creat = malloc(sizeof(DLinkNode));
creat->data = value;
creat->prev = NULL;
creat->next = NULL;
return creat;
}
//销毁节点
void Destroy(DLinkNode* node) {
free(node);
node = NULL;
}
//初始化双链表
void DLinklistInit(DLinkNode** phead) {
//非法输入
if(phead == NULL) {
perror("DLinklistInit");
exit(1);
}
*phead = Creat(0);
(*phead)->next = *phead;
(*phead)->prev = *phead;
}
//双链表头插
void DLinklistPushfront(DLinkNode* head, Datatype value) {
//非法输入
if(head == NULL) {
perror("pushfront");
return;
}
DLinkNode* new_node = Creat(value);
DLinkNode* tmp = head->next;
new_node->prev = head;
head->next = new_node;
new_node->next = tmp;
tmp->prev = new_node;
}
//双链表尾插
void DLinklistPushback(DLinkNode* head, Datatype value) {
//非法输入
if(head == NULL) {
perror("pushback");
return;
}
DLinkNode* new_node = Creat(value);
DLinkNode* tmp = head->prev;
new_node->next = head;
head->prev = new_node;
new_node->prev = tmp;
tmp->next = new_node;
}
//双链表头删
void DLinklistPopfront(DLinkNode* head) {
//非法输入
if(head == NULL) {
perror("popfront");
return;
}
DLinkNode* tmp = head->next;
head->next = tmp->next;
tmp->next->prev = head;
Destroy(tmp);
}
//双链表尾删
void DLinklistPopback(DLinkNode* head) {
//非法输入
if(head == NULL) {
perror("popback");
return;
}
DLinkNode* tmp = head->prev;
tmp->prev->next = head;
head->prev = tmp->next;
// tmp->prev->next = head;
// head->prev = tmp;
// Destroy(tmp);
}
//双链表中查找一个元素,返回节点的地址
DLinkNode* DlinklistFind(DLinkNode* head, Datatype to_find) {
//非法输入
if(head == NULL) {
perror("find");
return;
}
DLinkNode* cur = head->next;
while(cur != head) {
if(cur->data == to_find) {
return cur;
}
cur = cur->next;
}
return NULL;
}
//在指定元素位置之前插入元素
void DLinklistInsert(DLinkNode* head, DLinkNode* pos, Datatype value) {
//非法输入
if(head==NULL && pos==NULL) {
perror("insert");
return;
}
DLinkNode* pos_prev = pos->prev;
DLinkNode* new_node = Creat(value);
new_node->next = pos;
pos->prev = new_node;
new_node->prev = pos_prev;
pos_prev->next = new_node;
}
//在指定元素位置之后插入元素
void DLinklistInsertAfter(DLinkNode* head, DLinkNode* pos, Datatype value) {
//非法输入
if(head==NULL && pos==NULL) {
perror("insert after");
return;
}
DLinkNode* pos_after = pos->next;
DLinkNode* new_node = Creat(value);
new_node->next = pos_after;
pos_after->prev = new_node;
new_node->prev = pos;
pos->next = new_node;
}
// 删除指定位置元素
void DLinklistErase(DLinkNode* head, DLinkNode* pos) {
//非法输入
if(head==NULL && pos==NULL) {
perror("erase");
return;
}
DLinkNode* to_erase = pos;
to_erase->prev->next = to_erase->next;
to_erase->next->prev = to_erase->prev;
Destroy(to_erase);
}
// 删除指定元素
void DLinklistRemove(DLinkNode* head, Datatype value) {
//非法输入
if(head==NULL) {
perror("erase");
return;
}
DLinkNode* cur = head->next;
while(cur != head) {
if(cur->data == value) {
DLinklistErase(head, cur);
return;
}
cur = cur->next;
}
}
// 删除制定所有元素
void DLinklistRemoveAll(DLinkNode* head, Datatype value) {
//非法输入
if(head==NULL) {
perror("erase all");
return;
}
DLinkNode* cur = head->next;
while(cur != head) {
if(cur->data == value) {
DLinklistErase(head, cur);
}
cur = cur->next;
}
}
// 求双向表长度
size_t DLinklistSize(DLinkNode* head) {
//非法输入
if(head==NULL) {
perror("size");
return;
}
size_t count = 0;
DLinkNode* cur = head->next;
while(cur != head) {
count++;
cur = cur->next;
}
return count;
}
// 双向链表是否为空
int DLinklistEmpty(DLinkNode* head) {
//非法输入
if(head==NULL) {
perror("empty");
return;
}
if(head->next == head) {
return 0;
}
return 1;
}
/* ****************************************************************
* ***************************** Teae *****************************
* ****************************************************************/
// 函数头打印函数
#define FUNCTION() printf("===================================== %s =====================================\n", __FUNCTION__)
// 双链表打印函数
void print(DLinkNode* head, const char* msg){
// 非法输入
if(head == NULL) {
perror("print");
exit(1);
}
printf("%s\n", msg);
DLinkNode* cur = head->next;
// 正序打印
printf("正序打印:\n");
while(cur != head) {
printf("[%c | %p] ", cur->data, cur);
cur = cur->next;
}
printf("\n");
// 逆序打印
printf("逆序打印:\n");
cur = head->prev;
while(cur != head) {
printf("[%c | %p] ", cur->data, cur);
cur = cur->prev;
}
printf("\n");
}
// 头插测试
void TestPushfront() {
FUNCTION();
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushfront(head, 'a');
DLinklistPushfront(head, 'b');
DLinklistPushfront(head, 'c');
DLinklistPushfront(head, 'd');
print(head, "依次头插 a,b,c,d");
}
// 尾插测试
void TestPushback() {
FUNCTION();
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'b');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'd');
print(head, "依次尾插 a,b,c,d");
}
// 头删测试
void TestPopfront() {
FUNCTION();
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'b');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'd');
print(head, "依次尾插 a,b,c,d");
DLinklistPopfront(head);
DLinklistPopfront(head);
print(head, "头删两个");
DLinklistPopfront(head);
DLinklistPopfront(head);
print(head, "再头删两个");
DLinklistPopfront(head);
print(head, "头删空双向表");
}
// 尾删测试
void TestPopback() {
FUNCTION();
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'b');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'd');
print(head, "依次头插 a,b,c,d");
DLinklistPopback(head);
DLinklistPopback(head);
print(head, "头删两个");
DLinklistPopback(head);
DLinklistPopback(head);
print(head, "再头删两个");
DLinklistPopback(head);
print(head, "头删空双向表");
}
//查找一个元素返回节点地址测试
void TestFind() {
FUNCTION();
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'b');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'd');
print(head, "依次头插 a,b,c,d");
DLinkNode* ret = DlinklistFind(head, 'a');
printf("address is %p, data is %c\n", ret, ret->data);
}
//指定元素之前插入
void TestInsert() {
FUNCTION();
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'b');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'd');
print(head, "依次头插 a,b,c,d");
DLinkNode* pos = DlinklistFind(head, 'd');
DLinklistInsert(head, pos, 'X');
print(head, "在元素 d 之前插入元素 X");
}
//指定元素之后插入
void TestInsertAfter() {
FUNCTION();
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'b');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'd');
print(head, "依次头插 a,b,c,d");
DLinkNode* pos = DlinklistFind(head, 'd');
DLinklistInsertAfter(head, pos, 'X');
print(head, "在元素 d 之后插入元素 X");
}
//删除指定位置元素测试
void TestErase() {
FUNCTION();
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'b');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'd');
print(head, "依次头插 a,b,c,d");
DLinkNode* pos = DlinklistFind(head, 'a');
DLinklistErase(head, pos);
print(head, "删除a");
}
//删除指定元素
void TestRemove() {
FUNCTION();
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'd');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'b');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'd');
print(head, "c, a, d, c, b, c, a, d");
DLinklistRemove(head, 'a');
print(head, "删除第一次出现的元素a");
}
//删除指定所有元素
void TestRemoveAll() {
FUNCTION();
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'd');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'b');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'd');
print(head, "c, a, d, c, b, c, a, d");
DLinklistRemoveAll(head, 'a');
print(head, "删除所有的的元素a");
}
//链表长度测试
void TestSize() {
FUNCTION();
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'd');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'b');
DLinklistPushback(head, 'c');
DLinklistPushback(head, 'a');
DLinklistPushback(head, 'd');
print(head, "c, a, d, c, b, c, a, d");
size_t len = DLinklistSize(head);
printf("the length of doublie linklist is %d\n", len);
}
//删除链表测试
void TestEmpty() {
FUNCTION();
DLinkNode* head;
DLinklistInit(&head);
// DLinklistPushback(head, 'c');
// DLinklistPushback(head, 'a');
// DLinklistPushback(head, 'd');
// DLinklistPushback(head, 'c');
// DLinklistPushback(head, 'b');
// DLinklistPushback(head, 'c');
// DLinklistPushback(head, 'a');
// DLinklistPushback(head, 'd');
print(head, "c, a, d, c, b, c, a, d");
int ret = DLinklistEmpty(head);
printf("%d\n", ret);
}
int main() {
TestPushfront();
TestPushback();
TestPopfront();
TestPopback();
TestFind();
TestInsert();
TestInsertAfter();
TestErase();
TestRemove();
TestRemoveAll();
TestSize();
TestEmpty();
return 0;
}
测试函数部分采用的是单元测试模式
函数命名方式遵守的是 C++ STL 风格
以上代码实现环境Centos6.5,如有纰漏,请各位斧正