数据结构:双向链表的使用

双向链表

为什么需要双向链表?
在单链表中,有了next指针,这就使得要查找的下一个结点的时间复杂度为O(1),可是要查找是上一个结点的话,最坏的时间复杂度是O(n)了,所以为了克服这一缺点提出双向链表。

双向链表:双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。
双向链表中每个结点都有两个指针域:一个指向直接后继,一个指向直接前驱。

双向链表中循环的带头结点的空链表:
在这里插入图片描述

非空的循环的带头结点的双向链表:
在这里插入图片描述

(1)头文件:
在这里插入图片描述
实现代码:

#pragma once
//双向链表,带头结点,头的前驱为NULL,尾的后继为NULL

typedef struct DNode
{
	int data;
	struct DNode *next;//后继指针
	struct DNode *prio;//前驱指针
}DNode,*DList;

void InitList(DList plist);

bool Insert_head(DList plist,int val);//头插法

bool Insert_tail(DList plist,int val);//尾插法

DNode *Search(DList plist,int key);//查找

bool Delete(DList plist,int key);//删除

bool IsEmpty(DList plist);//判空

int GetLength(DList plist);//获取长度,数据个数

void Show(DList plist);//打印

DNode *Getprio(DList plist,int key);//获得key的前驱

DNode *GetNext(DList plist,int key);//获得key的后继

void Clear(DList plist);//清空

void Destory(DList plist);//销毁

(2)源文件:
在这里插入图片描述
实现代码:

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include"dlist.h"

void InitList(DList plist)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return ;
	}
	plist->next = NULL;
	plist->prio = NULL;
}

bool Insert_head(DList plist,int val)//头插法
{
	DNode *p = (DNode *)malloc(sizeof(DNode));
	p->data = val;

	p->next = plist->next;
	plist->next = p;
	p->prio = plist;

	if (p->next != NULL)
	{
		p->next->prio = p;
	}
	return true;
}

bool Insert_tail(DList plist,int val)//尾插法
{
	DNode *p = (DNode *)malloc(sizeof(DNode));
	p->data = val;

	DNode *q;
	for (q=plist; q->next != NULL;q=q->next);
	
	p->next = q->next;
	p->prio = q;
	q->next = p;
	
	return true;
}

DNode *Search(DList plist,int key)//查找
{
	for (DNode *p=plist->next; p!=NULL; p=p->next)
	{
		if (p->data == key)
		{
			return p;
		}
	}
	return NULL;
}

bool Delete(DList plist,int key)//删除
{
	DNode *p = Search(plist,key);
	if (p == NULL)
	{
		return false;
	}
	
	//将p从链表中剔除
	p->prio->next = p->next;
	if (p->next != NULL)
	{
		p->next->prio = p->prio;
	}
	free(p);
	return true;
}

bool IsEmpty(DList plist)//判空
{
	return plist->next == NULL;
}

int GetLength(DList plist)//获取长度,数据个数
{
	int count = 0;
	for (DNode *p=plist->next; p!=NULL; p=p->next)
	{
		count++;
	}
	return count;
}

void Show(DList plist)//打印
{
	for (DNode *p=plist->next; p!=NULL; p=p->next)
	{
		printf("%d \n",p->data);
	}
}

DNode *Getprio(DList plist,int key)//获得key的前驱
{
	assert(plist!=NULL);
	for (DNode *p=plist; p->next!=NULL; p=p->next)
	{
		if(p->next->data == key)
		{
			return p;
		}
	}
	return NULL;
}

DNode *GetNext(DList plist,int key)//获得key的后继
{
	DNode *p = Search(plist,key);

	if (p == NULL)
	{
		return NULL;
	}
	return p->next;
}

void Clear(DList plist)//清空
{
	Destory(plist);
}

void Destory(DList plist)//销毁
{
	DNode *p;
	while (plist->next != NULL)
	{
		p = plist->next;
		plist->next = p->next;
		free(p);
	}
}

测试用例:
1.尾插0-9
在这里插入图片描述
2.头插数字25
在这里插入图片描述

3.获取长度(把头插25去掉了)
在这里插入图片描述
4.查找8
在这里插入图片描述
5.查找前驱下标
在这里插入图片描述
6.查找后继下标
在这里插入图片描述
7.删除3
在这里插入图片描述
8.清空
在这里插入图片描述
9.销毁
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值