目录
[2.1 双向链表的初始化LTInit](#2.1 双向链表的初始化LTInit)
[2.2 双向链表的打印LTPrint](#2.2 双向链表的打印LTPrint)
[2.3 双向链表的判空LTEmpty](#2.3 双向链表的判空LTEmpty)
[2.4 尾插LTPushBack](#2.4 尾插LTPushBack)
[2.5 尾删LTPopBack](#2.5 尾删LTPopBack)
[2.6 头插LTPushFront](#2.6 头插LTPushFront)
[2.7 头删LTPopFront](#2.7 头删LTPopFront)
[2.8 查找LTFind](#2.8 查找LTFind)
[2.9 插入LTInsert](#2.9 插入LTInsert)
[2.10 删除LTErase](#2.10 删除LTErase)
[2.11 销毁LTDestroy](#2.11 销毁LTDestroy)
[4.1 ListNode.h](#4.1 ListNode.h)
[4.2 ListNode.c](#4.2 ListNode.c)
[4.3 test.c](#4.3 test.c)
一、双向链表的结构
双向链表的结构如下图所示:

二、双向链表的实现
2.1 双向链表的初始化LTInit
实现代码如下:
cpp
LTNode* BuyNode(LTDataType x) {
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (newnode == NULL) {
perror("BuyNode()::malloc");
exit(1);
}
newnode->next = newnode;
newnode->prev = newnode;
newnode->data = x;
return newnode;
}
LTNode* LTInit() {
return BuyNode(0);
}
2.2 双向链表的打印LTPrint
实现代码如下:
cpp
void LTPrint(LTNode* phead) {
assert(phead);
LTNode* cur = phead->next;
while (cur != phead) {
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
2.3 双向链表的判空LTEmpty
实现代码如下:
cpp
bool LTEmpty(LTNode* phead) {
if (phead->next == phead) {
return true;
}
else {
return false;
}
}
2.4 尾插LTPushBack
实现代码如下:
cpp
LTNode* BuyNode(LTDataType x) {
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (newnode == NULL) {
perror("BuyNode()::malloc");
exit(1);
}
newnode->next = newnode;
newnode->prev = newnode;
newnode->data = x;
return newnode;
}
void LTPushBack(LTNode* phead, LTDataType x) {
assert(phead);
LTNode* newnode = BuyNode(x);
LTNode* tail = phead->prev;
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
2.5 尾删LTPopBack
实现代码如下:
cpp
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(LTEmpty(phead) != true);
LTNode* tail = phead->prev;
LTNode* pretail = tail->prev;
pretail->next = phead;
phead->prev = pretail;
free(tail);
}
2.6 头插LTPushFront
实现代码如下:
cpp
LTNode* BuyNode(LTDataType x) {
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (newnode == NULL) {
perror("BuyNode()::malloc");
exit(1);
}
newnode->next = newnode;
newnode->prev = newnode;
newnode->data = x;
return newnode;
}
void LTPushFront(LTNode* phead, LTDataType x) {
assert(phead);
LTNode* newnode = BuyNode(x);
newnode->next = phead->next;
newnode->prev = phead;
phead->next = newnode;
newnode->next->prev = newnode;
}
2.7 头删LTPopFront
实现代码如下:
cpp
void LTPopFront(LTNode* phead) {
assert(phead);
LTNode* del = phead->next;
phead->next = del->next;
del->next->prev = phead;
free(del);
}
2.8 查找LTFind
实现代码如下:
cpp
LTNode* 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;
}
2.9 插入LTInsert
实现代码如下:
cpp
void LTInsert(LTNode* pos, LTDataType x){
assert(pos);
LTNode* newnode = BuyNode(x);
newnode->next = pos->next;
newnode->prev = pos;
pos->next = newnode;
newnode->next->prev = newnode;
}
2.10 删除LTErase
实现代码如下:
cpp
void LTErase(LTNode* pos) {
assert(pos);
LTNode* next = pos->next;
LTNode* prev = pos->prev;
next->prev = prev;
prev->next = next;
free(pos);
}
2.11 销毁LTDestroy
实现代码如下:
cpp
void LTDestroy(LTNode* phead) {
assert(phead);
LTNode* cur = phead->next;
while (cur!=phead) {
LTNode* next = cur->next;
free(cur);
cur = next;
}
phead->next = phead;
phead->prev = phead;
}
三、顺序表和和链表的优缺点分析
|--------------|------------------|-----------------|
| 不同点 | 顺序表 | 链表(单链表) |
| 存储空间上 | 物理上⼀定连续 | 逻辑上连续,但物理上不⼀定连续 |
| 随机访问 | ⽀持O(1) | 不⽀持:O(N) |
| 任意位置插⼊或者删除元素 | 可能需要搬移元素,效率低O(N) | 只需修改指针指向 |
| 插⼊ | 动态顺序表,空间不够时需要扩容 | 没有容量的概念 |
| 应⽤场景 | 元素⾼效存储+频繁访问 | 任意位置插⼊和删除频繁 |
四、代码
4.1 ListNode.h
cpp
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* prev;
LTDataType data;
struct ListNode* next;
}LTNode;
//void LTInit(LTNode** pphead);
LTNode* LTInit();
void LTDestroy(LTNode* phead);
void LTPrint(LTNode* phead);
bool LTEmpty(LTNode* phead);
void LTPushBack(LTNode* phead, LTDataType x);
void LTPopBack(LTNode* phead);
void LTPushFront(LTNode* phead, LTDataType x);
void LTPopFront(LTNode* phead);
//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x);
void LTErase(LTNode* pos);
LTNode* LTFind(LTNode* phead, LTDataType x);
4.2 ListNode.c
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"ListNode.h"
LTNode* BuyNode(LTDataType x) {
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (newnode == NULL) {
perror("BuyNode()::malloc");
exit(1);
}
newnode->next = newnode;
newnode->prev = newnode;
newnode->data = x;
return newnode;
}
LTNode* LTInit() {
return BuyNode(0);
}
void LTDestroy(LTNode* phead) {
assert(phead);
LTNode* cur = phead->next;
while (cur!=phead) {
LTNode* next = cur->next;
free(cur);
cur = next;
}
phead->next = phead;
phead->prev = phead;
}
void LTPrint(LTNode* phead) {
assert(phead);
LTNode* cur = phead->next;
while (cur != phead) {
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
bool LTEmpty(LTNode* phead) {
if (phead->next == phead) {
return true;
}
else {
return false;
}
}
void LTPushBack(LTNode* phead, LTDataType x) {
assert(phead);
LTNode* newnode = BuyNode(x);
LTNode* tail = phead->prev;
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(LTEmpty(phead) != true);
LTNode* tail = phead->prev;
LTNode* pretail = tail->prev;
pretail->next = phead;
phead->prev = pretail;
free(tail);
}
void LTPushFront(LTNode* phead, LTDataType x) {
assert(phead);
LTNode* newnode = BuyNode(x);
newnode->next = phead->next;
newnode->prev = phead;
phead->next = newnode;
newnode->next->prev = newnode;
}
void LTPopFront(LTNode* phead) {
assert(phead);
LTNode* del = phead->next;
phead->next = del->next;
del->next->prev = phead;
free(del);
}
LTNode* 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;
}
//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x){
assert(pos);
LTNode* newnode = BuyNode(x);
newnode->next = pos->next;
newnode->prev = pos;
pos->next = newnode;
newnode->next->prev = newnode;
}
void LTErase(LTNode* pos) {
assert(pos);
LTNode* next = pos->next;
LTNode* prev = pos->prev;
next->prev = prev;
prev->next = next;
free(pos);
}
4.3 test.c
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"ListNode.h"
void test01()//测试尾插
{
LTNode* phead = LTInit();
LTPushBack(phead, 1);
LTPushBack(phead, 2);
LTPushBack(phead, 3);
LTPushBack(phead, 4);
LTPrint(phead);
LTDestroy(phead);
}
void test02()//测试尾删
{
LTNode* phead = LTInit();
LTPushBack(phead, 1);
LTPushBack(phead, 2);
LTPushBack(phead, 3);
LTPushBack(phead, 4);
LTPrint(phead);//1 2 3 4
LTPopBack(phead);
LTPrint(phead);//1 2 3
LTPopBack(phead);
LTPrint(phead);//1 2
LTPopBack(phead);
LTPrint(phead);//1
LTPopBack(phead);
LTPrint(phead);//NULL
LTDestroy(phead);
}
void test03()//测试头插
{
LTNode* phead = LTInit();
LTPushFront(phead, 1);
LTPushFront(phead, 2);
LTPushFront(phead, 3);
LTPushFront(phead, 4);
LTPrint(phead);//4 3 2 1
}
void test04()//测试头删
{
LTNode* phead = LTInit();
LTPushFront(phead, 1);
LTPushFront(phead, 2);
LTPushFront(phead, 3);
LTPushFront(phead, 4);
LTPrint(phead);//4 3 2 1
LTPopFront(phead);
LTPrint(phead);
LTPopFront(phead);
LTPrint(phead);
LTPopFront(phead);
LTPrint(phead);
LTPopFront(phead);
LTPrint(phead);
}
void tect05()//测试查找
{
LTNode* phead = LTInit();
LTPushFront(phead, 1);
LTPushFront(phead, 2);
LTPushFront(phead, 3);
LTPushFront(phead, 4);
LTNode* ret = LTFind(phead, 4);
if (ret == NULL) {
printf("找不到\n");
}
else {
printf("找到了\n");
}
ret = LTFind(phead, 9);
if (ret == NULL) {
printf("找不到\n");
}
else {
printf("找到了\n");
}
}
void test06()//测试插入
{
LTNode* phead = LTInit();
LTPushFront(phead, 1);
LTPushFront(phead, 2);
LTPushFront(phead, 3);
LTPushFront(phead, 4);
LTNode* ret = LTFind(phead, 4);
LTInsert(ret, 99);
LTPrint(phead);
ret = LTFind(phead, 1);
LTInsert(ret, 88);
LTPrint(phead);
ret = LTFind(phead, 3);
LTInsert(ret, 77);
LTPrint(phead);
}
void test07()//测试删除
{
LTNode* phead = LTInit();
LTPushFront(phead, 1);
LTPushFront(phead, 2);
LTPushFront(phead, 3);
LTPushFront(phead, 4);
LTNode* ret = LTFind(phead, 4);
LTErase(ret);
LTPrint(phead);
ret = LTFind(phead, 3);
LTErase(ret);
LTPrint(phead);
ret = LTFind(phead, 2);
LTErase(ret);
LTPrint(phead);
ret = LTFind(phead, 1);
LTErase(ret);
LTPrint(phead);
}
int main() {
//test01();//测试尾插
//test02();//测试尾删
//test03();//测试头插
//test04();//测试头删
//tect05();//测试查找、
//test06();//测试插入
//test07();//测试删除
return 0;
}