双向链表的实现

目录

一、双向链表的结构

二、双向链表的实现

2.1 双向链表的初始化LTInit

2.2 双向链表的打印LTPrint

2.3 双向链表的判空LTEmpty

2.4 尾插LTPushBack

2.5 尾删LTPopBack

2.6 头插LTPushFront

2.7 头删LTPopFront

2.8 查找LTFind

2.9 插入LTInsert

2.10 删除LTErase

2.11 销毁LTDestroy

三、顺序表和和链表的优缺点分析

四、代码

4.1 ListNode.h

4.2 ListNode.c

4.3 test.c


一、双向链表的结构

双向链表的结构如下图所示:

二、双向链表的实现

2.1 双向链表的初始化LTInit

实现代码如下:

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

实现代码如下:

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

实现代码如下:

bool LTEmpty(LTNode* phead) {
	if (phead->next == phead) {
		return true;
	}
	else {
		return false;
	}
}

2.4 尾插LTPushBack

实现代码如下:

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

实现代码如下:

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

实现代码如下:

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

实现代码如下:

void LTPopFront(LTNode* phead) {
	assert(phead);
	LTNode* del = phead->next;
	phead->next = del->next;
	del->next->prev = phead;
	free(del);
}

2.8 查找LTFind

实现代码如下:

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

实现代码如下:

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

实现代码如下:

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

实现代码如下:

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

#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

#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

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值