目录
一、什么是双向链表
概念:双向链表(double linked list)也可称为带头双向循环链表。他的结构是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。所以在双向链表中的结点都有两个指针域,一个指向直接前驱,另一个指向直接后继。
这是双向链表的循环带头结点的空链表,它的直接前驱是它自己,它的直接后继也是它自己。
二、双向循环链表的定义
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* next;//后继
struct ListNode* prev;//前驱
LTDataType data;//数据域
}LTNode;
三、双向循环链表的一些接口函数
1、初始化
//初始化头节点(哨兵位)
LTNode* LTInit()
{
LTNode* phead = BuyLTNode(0);
//使其头尾相连成循环链表
phead->next = phead;
phead->prev = phead;
return phead;
}
2、动态开辟空间
//动态开辟空间
LTNode* BuyLTNode(LTDataType x)
{
LTNode* node = (LTNode*)malloc(sizeof(LTNode));
if (node == NULL)
{
perror("malloc faile");
exit(-1);
}
node->data = x;
node->next = NULL;
node->prev = NULL;
return node;
}
3、打印
//打印
void LTPrint(LTNode* phead)
{
assert(phead);
printf("phead<=>");
//使cur结点为头节点的next
LTNode* cur = phead->next;
while (cur != phead)
{
printf("%d<=>", cur->data);
cur = cur->next;
}
printf("\n");
}
4、尾插
//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* tail = phead->prev;
LTNode* newnode = BuyLTNode(x);
newnode->prev = tail;
tail->next = newnode;
newnode->next = phead;
phead->prev = newnode;
}
5、尾删
//尾删
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
LTNode* tail = phead->prev;
//tail前一个结点
LTNode* tailprev = tail->prev;
free(tail);
tailprev->next = phead;
phead->prev = tailprev;
}
6、头插
//头插
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = BuyLTNode(x);
newnode->next = phead->next;
phead->next->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
}
7、头删
//头删
void LTPopFront(LTNode* phead)
{
assert(phead);
//不是循环链表
assert(phead->next!=phead);
LTNode* first = phead->next;
LTNode* scend = first->next;
free(first);
phead->next = scend;
scend->prev = phead;
}
8、求链表大小
//链表大小
int LTsize(LTNode* phead)
{
assert(phead);
int size = 0;
//数据元素的个数,不包括哨兵位
LTNode* cur = phead->next;
while (cur != phead)
{
++size;
cur = cur->next;
}
return size;
}
9、pos之前插入x
//pos之前插入x
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* posPrev = pos->prev;
LTNode* newnode = BuyLTNode(x);
posPrev->next = newnode;
newnode->prev = posPrev;
pos->prev = newnode;
newnode->next = pos;
}
10、删除pos位置
void LTErase(LTNode* pos)
{
assert(pos);
LTNode* posPrev = pos->prev;
LTNode* posNext = pos->next;
free(pos);
posPrev->next = posNext;
posNext->prev = posPrev;
}
11、寻找x
//寻找x
void LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
return NULL;
}
12、销毁
//销毁
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}
13、一些对代码的改进
由于插入和删除的接口函数在后面才实现,所以现在对头插头删,尾插尾删这四个接口函数进行改进。
//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
/*LTNode* tail = phead->prev;
LTNode* newnode = BuyLTNode(x);
newnode->prev = tail;
tail->next = newnode;
newnode->next = phead;
phead->prev = newnode;*/
LTInsert(phead->prev, x);
}
//尾删
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
//LTNode* tail = phead->prev;
tail前一个结点
//LTNode* tailprev = tail->prev;
//free(tail);
//tailprev->next = phead;
//phead->prev = tailprev;
LTErase(phead->prev);
}
//头插
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
/*LTNode* newnode = BuyLTNode(x);
newnode->next = phead->next;
phead->next->prev = newnode;
phead->next = newnode;
newnode->prev = phead;*/
LTInsert(phead->next,x);
}
//头删
void LTPopFront(LTNode* phead)
{
assert(phead);
//不是循环链表
assert(phead->next!=phead);
/*LTNode* first = phead->next;
LTNode* scend = first->next;
free(first);
phead->next = scend;
scend->prev = phead;*/
LTErase(phead);
}
四、完整代码
头文件 List.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* next;//后继
struct ListNode* prev;//前驱
LTDataType data;//数据域
}LTNode;
//动态开辟空间
LTNode* BuyLTNode(LTDataType x);
//初始化
LTNode* LTInit();
//打印
void LTPrint(LTNode* head);
//尾插
void LTPushBack(LTNode* head, LTDataType x);
//尾删
void LTPopBack(LTNode* head);
//头插
void LTPushFront(LTNode* head, LTDataType x);
//头删
void LTPopFront(LTNode* head);
//链表大小
int LTsize(LTNode* head);
//pos之前插入x
void LTInsert(LTNode* pos, LTDataType x);
//删除pos位置
void LTErase(LTNode* pos);
//寻找x
void LTFind(LTNode* head, LTDataType x);
//销毁
void LTDestroy(LTNode* head);
源文件 List.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"
//动态开辟空间
LTNode* BuyLTNode(LTDataType x)
{
LTNode* node = (LTNode*)malloc(sizeof(LTNode));
if (node == NULL)
{
perror("malloc faile");
exit(-1);
}
node->data = x;
node->next = NULL;
node->prev = NULL;
return node;
}
//初始化头节点(哨兵位)
LTNode* LTInit()
{
LTNode* phead = BuyLTNode(0);
//使其头尾相连成循环链表
phead->next = phead;
phead->prev = phead;
return phead;
}
//打印
void LTPrint(LTNode* phead)
{
assert(phead);
printf("phead<=>");
//使cur结点为头节点的next
LTNode* cur = phead->next;
while (cur != phead)
{
printf("%d<=>", cur->data);
cur = cur->next;
}
printf("\n");
}
//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
/*LTNode* tail = phead->prev;
LTNode* newnode = BuyLTNode(x);
newnode->prev = tail;
tail->next = newnode;
newnode->next = phead;
phead->prev = newnode;*/
LTInsert(phead->prev, x);
}
//尾删
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
//LTNode* tail = phead->prev;
tail前一个结点
//LTNode* tailprev = tail->prev;
//free(tail);
//tailprev->next = phead;
//phead->prev = tailprev;
LTErase(phead->prev);
}
//头插
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
/*LTNode* newnode = BuyLTNode(x);
newnode->next = phead->next;
phead->next->prev = newnode;
phead->next = newnode;
newnode->prev = phead;*/
LTInsert(phead->next,x);
}
//头删
void LTPopFront(LTNode* phead)
{
assert(phead);
//不是循环链表
assert(phead->next!=phead);
/*LTNode* first = phead->next;
LTNode* scend = first->next;
free(first);
phead->next = scend;
scend->prev = phead;*/
LTErase(phead);
}
//链表大小
int LTsize(LTNode* phead)
{
assert(phead);
int size = 0;
//数据元素的个数,不包括哨兵位
LTNode* cur = phead->next;
while (cur != phead)
{
++size;
cur = cur->next;
}
return size;
}
//pos之前插入x
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* posPrev = pos->prev;
LTNode* newnode = BuyLTNode(x);
posPrev->next = newnode;
newnode->prev = posPrev;
pos->prev = newnode;
newnode->next = pos;
}
//删除pos位置
void LTErase(LTNode* pos)
{
assert(pos);
LTNode* posPrev = pos->prev;
LTNode* posNext = pos->next;
free(pos);
posPrev->next = posNext;
posNext->prev = posPrev;
}
//寻找x
void LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
return NULL;
}
//销毁
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}
源文件 Test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"
void TestList1()
{
LTNode* plist = LTInit();
LTPushBack(plist, 1);
LTPushBack(plist, 2);
LTPushBack(plist, 3);
LTPushBack(plist, 4);
LTPushBack(plist, 5);
LTPrint(plist);
LTPushFront(plist, 10);
LTPushBack(plist, 10);
LTPrint(plist);
}
void TestList2()
{
LTNode* plist = LTInit();
LTPushBack(plist, 1);
LTPushBack(plist, 2);
LTPushBack(plist, 3);
LTPushBack(plist, 4);
LTPushBack(plist, 5);
LTPrint(plist);
LTPopBack(plist);
LTPopFront(plist);
LTPrint(plist);
LTPopFront(plist);
LTPrint(plist);
LTPopFront(plist);
LTPrint(plist);
LTPopFront(plist);
//LTPopFront(plist);
LTPrint(plist);
}
void TestList3()
{
LTNode* plist = LTInit();
LTPushBack(plist, 1);
LTPushBack(plist, 2);
LTPushBack(plist, 3);
LTPushBack(plist, 4);
LTPushBack(plist, 5);
LTPrint(plist);
LTPushFront(plist, 10);
LTPushFront(plist, 20);
LTPushFront(plist, 30);
LTPushFront(plist, 40);
LTPrint(plist);
}
void TestList4()
{
LTNode* plist = LTInit();
LTPushBack(plist, 1);
LTPushBack(plist, 2);
LTPushBack(plist, 3);
LTPushBack(plist, 4);
LTPushBack(plist, 5);
LTPrint(plist);
LTPopFront(plist);
LTPrint(plist);
LTPopBack(plist);
LTPrint(plist);
}
int main()
{
TestList2();
return 0;
}