【数据结构】05.双向链表

一、双向链表的结构

注意:这里的"带头"跟前面我们说的"头节点"是两个概念,带头链表里的头节点,实际为"哨兵位",哨兵位节点不存储任何有效元素,只是站在这里"放哨的"。

"哨兵位"存在的意义:遍历循环链表避免死循环。

二、双向链表的实现

2.1 双向链表结点的创建

c 复制代码
typedef int DLType;
//创建结构体
typedef struct DList
{
	DLType data;
	struct DList* prev;
	struct DList* next;
}DL;

2.2 双向链表的初始化与销毁

c 复制代码
//初始化phead
DL* init(void)
{
	DL* phead = BuyNewNode(0);
	return phead;
}
c 复制代码
//销毁链表,这里需要主要phead是形参,这里的最后将phead置空并不能将原链表中的phead置空,
//因此原链表中的phead需要手动置空,详细实现见源码
void DLDesdroy(DL* phead)
{
	assert(phead);
	DL* tail =phead->next;
 
	while (tail != phead)
	{
		DL* next = tail->next;
		free(tail); 
		tail= next;
	}
	free(phead);
	phead = NULL;
}

2.3 双向链表的增删查改

由于多次创建结点,因此我们将它提炼为一个函数

c 复制代码
//创造新的节点
DL* BuyNewNode(DLType  x)
{
	DL* newnode = (DL*)malloc(sizeof(DL));
	if (newnode == NULL)
	{
		perror("malloc is failed!\n");
		return 1;
	}
	newnode->data = x;
	newnode->next = newnode->prev = newnode;
	return newnode;
}
c 复制代码
//尾插
void  DLPushBack(DL* phead,DLType x)
{
	assert(phead);
 
	DL* newnode = BuyNewNode(x);
 
	newnode->next = phead;
	phead->prev->next = newnode;
 
	newnode->prev = phead->prev;
	phead->prev = newnode;
}
 
 
//尾删
void DLPopBack(DL* phead)
{
	assert(phead);
	assert(phead->next != phead);
 
	DL* tail = phead->prev;
	DL* prev = tail->prev;
 
	prev->next = phead;
	phead->prev = prev;
	free(tail);
	tail = NULL;  
 
}
 
//头插
void DLPushFront(DL* phead, DLType x)
{
	assert(phead);
 
	DL* newnode = BuyNewNode(x);
 
	DL* first = phead->next;
 
	newnode->next = first;
	first->prev = newnode;
	phead->next = newnode;
	newnode->prev=phead;
}
 
//头删
void DLPopFront(DL* phead)
{
	assert(phead);
	assert(phead->next != phead);
 
	DL* first = phead->next;
	DL* second = first->next;
 
	phead->next = second;
	second->prev = phead;
 
	free(first);
	first = NULL;
}
 
 
//查找
DL* DLFind(DL* phead,DLType x)
{
	assert(phead);
 
	DL* cur = phead->next;
	while ( cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}
 
 
 
//pos位置插入数据
void DLInsert(DL* pos,DLType x)
{
	assert(pos);
 
	DL* newnode = BuyNewNode(x);
	DL* prev = pos->prev;
    
	prev->next = newnode;
	newnode->prev = prev;
 
    newnode->next = pos;
	pos->prev = newnode;
}
 
//pos位置之后插入数据
void DLInsertAfter(DL* pos, DLType x)
{
	assert(pos);
 
	DL* newnode = BuyNewNode(x);
	DL* next = pos->next;
 
	newnode->next = next;
	next->prev = newnode;
	pos->next = newnode;
	newnode->prev = pos;
}
 
//删除pos位置元素
void  DLErase(DL* pos)
{
	assert(pos);
 
	DL* next = pos->next;
	DL* prev = pos->prev;
 
	prev->next = next;
	next->prev = prev;
 
	free(pos);
	pos = NULL;
}

2.4 双向链表的打印

c 复制代码
//打印链表
void DLPrint(DL* phead)
{
	DL* pcur = phead->next;
	while (pcur != phead)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");
}

2.5 双向链表的源码

c 复制代码
//DL.h
 
#pragma once
 
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
 
typedef int DLType;
 
typedef struct DList
{
	DLType data;
	struct DList* prev;
	struct DList* next;
}DL;
 
//初始化
DL* init(void);
//打印
void DLPrint(DL* phead);
 
//尾插、尾删
void  DLPushBack(DL* phead, DLType x);
void DLPopBack(DL* phead);
 
//头插、头删
void  DLPushFront(DL* phead, DLType x);
void  DLPopFront(DL* phead);
 
//查找
DL* DLFind(DL* phead, DLType x);
 
//指定位置插入数据、指定位置之后插入数据
void  DLInsert(DL* pos, DLType x);
void DLInsertAfter(DL* pos, DLType x);
 
//删除pos
void  DLErase(DL* phead);
 
void DLDesdroy(DL** phead);
c 复制代码
//DL.c
#include "DList.h"
 
 
//创造新的节点
DL* BuyNewNode(DLType  x)
{
	DL* newnode = (DL*)malloc(sizeof(DL));
	if (newnode == NULL)
	{
		perror("malloc is failed!\n");
		return 1;
	}
	newnode->data = x;
	newnode->next = newnode->prev = newnode;
	return newnode;
}
 
 
//初始化phead
DL* init(void)
{
	DL* phead = BuyNewNode(0);
	return phead;
}
 
 
//打印链表
void DLPrint(DL* phead)
{
	DL* pcur = phead->next;
	while (pcur != phead)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");
}
 
 
//尾插
void  DLPushBack(DL* phead,DLType x)
{
	assert(phead);
 
	DL* newnode = BuyNewNode(x);
 
	newnode->next = phead;
	phead->prev->next = newnode;
 
	newnode->prev = phead->prev;
	phead->prev = newnode;
}
 
 
//尾删
void DLPopBack(DL* phead)
{
	assert(phead);
	assert(phead->next != phead);
 
	DL* tail = phead->prev;
	DL* prev = tail->prev;
 
	prev->next = phead;
	phead->prev = prev;
	free(tail);
	tail = NULL;  
 
}
 
//头插
void DLPushFront(DL* phead, DLType x)
{
	assert(phead);
 
	DL* newnode = BuyNewNode(x);
 
	DL* first = phead->next;
 
	newnode->next = first;
	first->prev = newnode;
	phead->next = newnode;
	newnode->prev=phead;
}
 
//头删
void DLPopFront(DL* phead)
{
	assert(phead);
	assert(phead->next != phead);
 
	DL* first = phead->next;
	DL* second = first->next;
 
	phead->next = second;
	second->prev = phead;
 
	free(first);
	first = NULL;
}
 
 
//查找
DL* DLFind(DL* phead,DLType x)
{
	assert(phead);
 
	DL* cur = phead->next;
	while ( cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}
 
 
 
//pos位置插入数据
void DLInsert(DL* pos,DLType x)
{
	assert(pos);
 
	DL* newnode = BuyNewNode(x);
	DL* prev = pos->prev;
    
	prev->next = newnode;
	newnode->prev = prev;
 
    newnode->next = pos;
	pos->prev = newnode;
}
 
//pos位置之后插入数据
void DLInsertAfter(DL* pos, DLType x)
{
	assert(pos);
 
	DL* newnode = BuyNewNode(x);
	DL* next = pos->next;
 
	newnode->next = next;
	next->prev = newnode;
	pos->next = newnode;
	newnode->prev = pos;
}
 
//删除
void  DLErase(DL* pos)
{
	assert(pos);
 
	DL* next = pos->next;
	DL* prev = pos->prev;
 
	prev->next = next;
	next->prev = prev;
 
	free(pos);
	pos = NULL;
}
 
//销毁链表
void DLDesdroy(DL* phead)
{
	assert(phead);
	DL* tail =phead->next;
 
	while (tail != phead)
	{
		DL* next = tail->next;
		free(tail); 
		tail= next;
	}
	free(phead);
	phead = NULL;
}
相关推荐
FakeOccupational8 分钟前
【电路笔记 通信】AXI4-Lite协议 FPGA实现 & Valid-Ready Handshake 握手协议
笔记·fpga开发
小明的小名叫小明17 分钟前
区块链技术原理(14)-以太坊数据结构
数据结构·区块链
pusue_the_sun18 分钟前
数据结构——栈和队列oj练习
c语言·数据结构·算法··队列
Dontla1 小时前
Makefile介绍(Makefile教程)(C/C++编译构建、自动化构建工具)
c语言·c++·自动化
奶黄小甜包1 小时前
C语言零基础第18讲:自定义类型—结构体
c语言·数据结构·笔记·学习
想不明白的过度思考者1 小时前
数据结构(排序篇)——七大排序算法奇幻之旅:从扑克牌到百亿数据的魔法整理术
数据结构·算法·排序算法
一支闲人1 小时前
C语言相关简单数据结构:双向链表
c语言·数据结构·链表·基础知识·适用于新手小白
姜不吃葱2 小时前
【力扣热题100】双指针—— 接雨水
数据结构·算法·leetcode·力扣热题100
拂晓银砾2 小时前
Java数据结构-队列
java·数据结构
John.Lewis2 小时前
数据结构初阶(19)外排序·文件归并排序的实现
c语言·数据结构·排序算法