双向链表的实现

目录

一、双向链表的结构

二、双向链表的实现

[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;
}
相关推荐
小张成长计划..2 小时前
数据结构-栈的实现
开发语言·数据结构
一只鱼^_5 小时前
基础算法合集-图论
数据结构·算法·深度优先·图论·广度优先·宽度优先·图搜索算法
s153356 小时前
数据结构之顺序表,链表,栈,队列
数据结构·数据库
Wo3Shi4七6 小时前
双向队列
数据结构·算法·go
Wo3Shi4七6 小时前
列表
数据结构·算法·go
Wo3Shi4七6 小时前
链表
数据结构·算法·go
Wo3Shi4七7 小时前
数组
数据结构·算法·go
北方有星辰zz7 小时前
数据结构:栈
java·开发语言·数据结构
zl_dfq7 小时前
数据结构之 【树的简介】(树的(相关)概念、二叉树的概念、部分性质、满二叉树、完全二叉树)
数据结构