【数据结构】第二章线性表:双链表、静态链表、循环链表、静态链表、顺序表与链表比较

本文详细介绍了双链表、循环链表和静态链表的概念、操作以及它们之间的比较。双链表允许双向遍历,循环链表最后一个节点指向头结点,静态链表则是利用数组实现的链表,适用于数据元素数量固定的场景。文章还探讨了顺序表和链表在逻辑结构、存储结构和操作上的优缺点,并提供了何时选择使用顺序表或链表的指导原则。
摘要由CSDN通过智能技术生成

目录

2.3_5 双链表

一、双链表的定义

二、双链表的初始化(带头结点)

三、双链表的插入

四、双链表的删除与销毁

五、双向链表的后向、前向遍历

2.3_6 循环链表

一、循环单链表的定义、初始化、判空、判表尾结点

二、循环双链表定义、初始化、判空

三、循环双链表的插入

四、循环双链表删除

2.3_7 静态链表

一、什么是静态链表

二、静态链表的定义

三、静态链表的基本操作

2.3_8 顺序表和链表比较

一、逻辑结构方面的比较

二、存储结构方面的比较

三、基本操作

四、什么时候用顺序表或者链表?


2.3_5 双链表

第二章单链表中学到:

单链表:无法逆向检索,有时候不太方便;

双链表:双向链表,可进可退,存储密度更低;

存储密度 = (结点数据本身所占的存储量)/(结点结构所占的存储总量)

计算结构体大小时需要考虑其内存布局,结构体在内存中存放是按单元存放的,每个单元多大取决于结构体中最大基本类型的大小。

一、双链表的定义

// 双向链表定义
typedef struct DNode{  // 定义双链表结点类型 
	ElemType data;  // 数据域
	struct DNode *prior, *next;  // 前驱和后继指针 
}DNode, *DLinklist; 

二、双链表的初始化(带头结点)

#include <iostream>
using namespace std;

typedef int ElemType;  // 数据域元素为int型 

// 双向链表定义
typedef struct DNode{  // 定义双链表结点类型 
	ElemType data;  // 数据域
	struct DNode *prior, *next;  // 前驱和后继指针 
}DNode, *DLinklist; 

// 初始化双链表
bool InitDLinkList(DLinklist &L){
	L = (DNode *)malloc(sizeof(DNode));  // 分配一个头结点
	if(L == NULL){  // 内存不足,分配失败 
		return false;
	} 
	L->prior = NULL;  // 头结点的prior永远指向NULL
	L->next = NULL;  // 头结点之后暂时还没有结点
	return true; 
} 

// 判断双链表是否为空(带头结点)
bool Empty(DLinklist L){
	if(L->next == NULL){
		return true;
	}else{
		return false;
	}
}

int main(){
	// 定义并初始化一个双向链表 
	DLinklist L;
	InitDLinkList(L);
	
	return 0;
}

初始化双向链表传参时使用的是 DLinklist &L 想强调的是,这里引用了一个双向链表;分配头结点时使用 DNode * 想强调的是 malloc 出了一个结点

DLinklist 与 DNode * 是等价的。

三、双链表的插入

// 在p结点之后插入s结点
bool InsertNextDNode(DNode *p, DNode *s){
	s->next = p->next;  // 为新结点s的后继指针赋值 
	p->next->prior = s;  // 为p后的旧结点的前驱赋指针值 
	s->prior = p;  // 为新结点s的前驱指针赋值 
	p->next = s;  // 为p后继指针赋值 
} 

如果p恰好是最后一个结点,就不用再做第二步 p->next->prior = s;  // 为p后的旧结点的前驱赋指针值 了,所以为了更加严谨,单独做一个判断,判断p结点是否为最后一个结点。

// 在p结点之后插入s结点(增加对p结点为最后一个结点的判断)
bool InsertNextDNode(DNode *p, DNode *s){
	if(P == NULL || s == NULL){  // 非法参数 
		return false;
	}
	s->next = p->next; // 为新结点s的后继指针赋值
	if(p->next != NULL){  // 如果p结点有后续结点 
		p->next->prior = s;  // 为p后的旧结点的前驱指针赋值 
	} 
	s->prior = p;  // 为新结点s的前驱指针赋值 
	p->next = s;  // 为p后继指针赋值 
	return true;
}

在p结点之后插入s结点新结点称为后插操作;想要完成按位序插入前插操作,则需找到p的前驱结点,做p前驱结点的后插操作。

四、双链表的删除与销毁

// 删除p结点的后继结点
bool DeleteNextDNode(DNode *p){
	if(p == NULL){  // 非法参数 
		return false;
	}
	DNode *q = p->next;  // 找到p的后继结点q
	if(q == NULL){  // q没有后继结点 
		return false;
	} 
	if(q->next !
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值