Bootstrap

【数据结构】第二章线性表:单链表的定义、插入和删除、查找、建立

目录

2.3_1 单链表的定义 

一、什么是单链表 

 二、用代码定义一个单链表

(1)结构体变量和结构体类型的定义

(2)不带头结点的链表

(3)带头结点的单链表

(4)头指针和头结点的理解

2.3_2 单链表插入和删除

一、按位序插入(带头结点)

 二、按位序插入(不带头结点)

三、指定结点的后插操作

四、指定结点的前插操作

五、按位序删除(带头结点)

六、指定结点的删除

小结Tips:

2.3.2.2 单链表的查找

 一、按位查找

二、按值查找

 三、求单链表长度(带头结点)

2.3.2.3_4 单链表的建立

一、尾插法建立单链表

二、头插法建立单链表


2.3_1 单链表的定义 

一、什么是单链表 

用链式存储的线性表统称为链表。

 二、用代码定义一个单链表

(1)结构体变量和结构体类型的定义

首先,我们按照之前 C/C++ 中学过的语法来定义一个结构体时是这样的:

struct LNode{  // 定义单链表结点类型 
	ElemType data;  // 数据域 
	struct LNode *next;  // 指针域 
}; 

// 在内存中申请一个结点所需的空间,并用指针p指向这个结点 
struct LNode *p = (struct LNode *)malloc(sizeof(struct LNode));

一句代码写得很长,有一个更方便的写法,引入 typedef 关键字进行数据类型重命名,把全名自定义成自己起的小名,使用起来更快捷。

typedef <数据类型> <别名>; 

typedef 关键字,将 struct LNode 这个结构体类型名字重新定义 LNode 和 *LinkList(用来表示指向struct LNmde的指针);

下次想定义一个 struct LNode 结构体变量时,直接 LNode 变量名,就可以了;

初次修改代码为:

struct LNode{
	ElemType data;
	sruct LNode *next;
};
typedef struct LNode LNode;

// 在使用它生成新结点时的代码:
LNode *p = (LNode *)malloc(sizeof(LNode)); 

参考菜鸟教程链接:结构体变量和结构体类型的定义 | 菜鸟教程

 *LinkList 是结构体指针,使用结构体指针对结构成员的访问(比如做遍历输出数据域时),与结构变量对结构成员的访问在表达方式上有所不同,结构指针对结构成员的访问表示为:结构指针名 -> 结构成员(与 . 优先级有关)

增加一个结构体指针之后的代码:

struct LNode{
	ElemType data;
	sruct LNode *next;
};
typedef struct LNode LNode;
typedef struct Lnode *LinkList;

// 在使用它生成新结点时的代码:
// 要表示一个单链表时,只需要声明一个头指针L,指向单链表的第一个结点
LNode *L;  // 声明一个指向单链表第一个结点的指针
// 或
LinkList L; 

而它的效果和下面的代码是一样的,所以我们定义单链表时用如下形式LNode * 强调“返回的是一个结点”LinkList 强调“这是一个单链表”,两者根据不同的场景使用会使代码可读性更高。

// 单链表定义
typedef struct LNode{  // 定义单链表结点类型 
	ElemType data;  // 每个结点存放一个数据元素
	struct LNode *next;  // 指针指向下一个结点 
}LNode, *LinkList; 

(2)不带头结点的链表

// 20220331 补充代码
// 2.3_1 单链表的定义——不带头结点的链表初始化、判空  
#include<iostream>
using namespace std;

# define ElemType int

typedef struct LNode{  // 定义单链表结点类型 
	ElemType data;  // 每个结点存放一个数据元素
	struct LNode *next;  // 指针指向下一个结点 
}LNode, *LinkList; 

// 初始化一个空的单链表
bool InitList(LinkList &L){
	L = NULL;  // 空表,暂时还没有任何结点(防止脏数据) 
	return true;
}

// 判断单链表是否为空
bool Empty(LinkList L){
	return (L == NULL); 
} 
 
int main(){
	// 声明一个不带头结点的单链表L 
	LinkList L;
	
	// 初始化
	bool InitFlag = 0;
	InitFlag = InitList(L);
	if(InitFlag) cout << "该不带头结点的单链表初始化成功!" << endl;
	else cout << "该不带头结点的单链表初始化不成功。" << endl;
	
	// 判空
	bool EmptyFlag = 0;
	EmptyFlag = Empty(L);
	if(Empty(L)) cout << "该表为空!" << endl;
	else cout << "该表不为空。" << endl; 
	
	return 0;
}

(3)带头结点的单链表

// 20220401 补充代码
// 2.3_1 单链表的定义——带头结点链表的初始化、判空
#include <iostream>
#include <cstdlib>
using namespace std;

#define ElemType int

typedef struct LNode{  // 定义单链表结点类型 
	ElemType data;  // 每个结点存放一个数据元素
	struct LNode *next;  // 指针指向下一个结点 
}LNode, *LinkList;

// 初始化一个单链表(带头结点)
bool InitList(LinkList &L){
	L = (LNode *)malloc(sizeof(LNode));  // 分配一个头结点
	if(L == NULL) return false;  // 内存不足,分配失败
	L->next = NULL;  // 头结点之后暂时还没有结点
	return true; 
} 

// 判断单链表是否为空(带头结点) 
bool Empty(LinkList L){
	return (L->next == NULL);
} 

int main(){
	// 声明一个指向单链表的指针
	
;