线性表——链式存储结构实现(双链表)

0.概述
本文主要介绍了双链表、循环链表(单、双),其次用代码实现了循环双链表的基本操作,代码实现值得注意的有以下几点:

1. 代码主要实现结点后删除和插入功能、按位查找、头插法建立双链表等,通过 封装 代码的思想实现双链表的插入和删除(eg:先按位查找到结点p,然后对结点p进行结点后插入或删除

2. 双链表其余基本操作(eg:长度、按值查找、尾插法等)与单链表逻辑相同,具体可参考我的另一篇博客:线性表——链式存储结构实现(单链表).


1.双链表基本知识
在这里插入图片描述


2.循环链表基本知识
在这里插入图片描述
时间复杂度分析(L指向表尾的)在这里插入图片描述

3.双链表基本操作(代码实现)

带头结点

在这里插入代码片#include<bits/stdc++.h>
using namespace std;

//双链表结点 
typedef struct DNode{
	int data;
	struct DNode *prior,*next;	
}DNode,*DLinkList;

//0.初始化双链表
void InitList(DLinkList &L){
	L=(DNode *)malloc(sizeof(DNode));
	L->next=NULL;
	L->prior=NULL;
} 

//1.指定结点后插入新结点 
bool InsertNextNode(DNode *p,DNode *s){
	if(p==NULL||s==NULL){
		return false;
	}
	s->next=p->next;
	
	if(p->next!=NULL){	//p结点不是最后一个结点 
		p->next->prior=s; 
	}
	
	s->prior=p;
	p->next=s;
	
	return true;
} 

//2.删除指定结点的后继结点
bool DeleteNextNode(DNode *p){
	if(p==NULL){
		return false;
	}
	
	DNode *q=p->next;	//	方便释放删除结点的存储空间 
	
	if(q==NULL){	//判断p结点是否为最后一个结点 
		return false;
	}	
	
	p->next=q->next;	//p不为最后一个结点时 
	
	if(q->next!=NULL){	//判断q是否为最后一个结点 
		q->next->prior=q; 
	}
	
	free(q);	//	释放所删除的结点 
	return true; 
} 

//3.按位查找结点
DNode * Get(DLinkList L,int i){
	if(i<1){
		return NULL;
	}
	
	DNode *p;	//	p指向正在扫描的结点 
	int j=0;	// p扫描到第几个结点 
	p=L;	//	p指向第一个结点 
	
	while(p!=NULL&&j<i){
		p=p->next;
		j++;
	}
	
	if(p==NULL){	//i值不合法 
		return NULL;	
	}
	return p; 
} 

//4.遍历
void PrintList(DLinkList L){
	DNode *p=L;
	while(p->next!=NULL){
		p=p->next;
		cout<<p->data<<" ";
	}
} 

//5.头插法创建双链表
DLinkList HeadCreateList(int a[],int n){
	DLinkList L=(DNode *)malloc(sizeof(DNode));
	L->next=NULL;
	L->prior=NULL;
	DNode *s;	//	指向新的双链表存储结点 
	
	for(int i=0;i<n;i++){
		s=(DNode *)malloc(sizeof(DNode));	//为新双链表结点分配存储空间 
		s->data=a[i];
		s->next=L->next;
		s->prior=L;
		L->next=s;
	}
	return L;
} 

//主程序 
int main(){
	
	//1.测试头插法创建双链表 遍历
	int a[]={1,2,3,4,5,6};
	DLinkList L=HeadCreateList(a,sizeof(a)/sizeof(a[0])); 
	PrintList(L);
	
	//2.删除结点3 
//	DNode *p=Get(L,2);
//	
//	if(p==NULL){
//		cout<<"查找删除前置结点失败!"<<endl;
//	}else{
//		if(DeleteNextNode(p)){
//			cout<<"删除成功!"<<endl;
//			PrintList(L); 
//		}else{
//			cout<<"删除失败!"<<endl;
//		}	
//	}
	
	//3.在结点3后插入新结点 
	DNode *p=Get(L,3);
	DNode *s=(DNode *)malloc(sizeof(DNode));
	s->data=8;
	s->next=NULL;
	s->prior=NULL;
	
	if(p==NULL){
		cout<<"查找删除前置结点失败!"<<endl;
	}else{
		if(InsertNextNode(p,s)){
			cout<<"插入成功!"<<endl;
			PrintList(L); 
		}else{
			cout<<"插入失败!"<<endl;
		}	
	}
	
	return 0;
} 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线性的链存储结构是使用链线性中的元素存储起来。链表可以分为单链表、循环链表和双链表。在单链表中,每个结点都包含指向下一个结点的指针。循环链表是在单链表的基础上,将最后一个结点的指针指向头结点,形成一个循环。而双链表则是在单链表的基础上,每个结点都包含指向前一个结点和后一个结点的指针。链表存储单元可以是连续的,也可以是非连续的,甚至是零散分布在内存的任何位置上。因此,链表中结点的逻辑顺序和物理顺序不一定相同。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [数据结构——线性的链存储](https://blog.csdn.net/weixin_46272350/article/details/119612209)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [线性的链存储结构..](https://download.csdn.net/download/N201871643/86035198)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值