数据结构2--链表

1. 链表的概念

单链表: 线性表的链接存储结构

存储思想: 用一组任意的存储单元存放线性表的元素

  • 不连续
  • 零散分布

单链表的存储特点:

  1. 逻辑次序和物理次序不一定相同
  2. 元素之间的逻辑关系用指针表示

例如:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

单链表是由若干个结点构成
单链表的结点只有一个指针域

单链表的结点结构

在这里插入图片描述

代码定义

typedef struct node
{
	Data data;  //数据域
	syruct node *next; //指针域
}Node, *Link;  //Node 等价于 struct node  , Link 等价于 struct node *

如何申请一个结点

p = (Link) malloc (sizeof(Node))

如何引用数据域,指针域

p->data
p->next

存储结构

头结点: 在单链表的第一个元素结点之前附设一个类型相同的结点,以便空表和非空表处理统一

头指针: 指向第一个结点的地址

尾标志: 终端结点的指针域为空

在这里插入图片描述
在这里插入图片描述

2. 单链表的实现

2.1 单链表的遍历

void displayNode(Link head)
{
	p = head->next;  //   p指向了链表的第一个有效数据的结点
	while(p != NULL)
	{
		printf("%d\n",p->data);
		p = p->next;
	}
}

在这里插入图片描述

2.2 求单链表的元素个数

在这里插入图片描述

伪算法:

  1. 工作指针 p 初始化,累加器 count 初始化

  2. 重复执行下述操作,直到 p 为空:
    工作指针 p 后移
    count ++

  3. 返回累加器 count 的值

int length(Link head)
{
	p = head->next;
	count = 0;
	while(p != NULL)
	{
		p = p->next;
		count++;
	}
	return count;
}

2.3 单链表的查找操作

bool queryNode(Link head, Data x)
{
	p = head->next;
	while(p!=NULL)
	{
		if(p->data == x)
		{
			printf(data);
			return true;
		}
		p = p->next;
	}
	// 如果循环结束,说明没有找到
	return false;
}

2.4 单链表的插入操作

在这里插入图片描述
在这里插入图片描述
让 p 移动到正确的位置

node = (Link) malloc (sizeof(Node));
node->data = x;
node->next = p->next;
p->next = node;

由于单链表带头结点,表头,表中,表尾三种情况的操作语句一致

伪算法

  1. 工作指针 p 初始化
  2. 查找第 i-1 个结点并使工作指针 p 指向该结点
  3. 若查找不成功,则返回 false
    否则:
    生成一个元素值为 x 的新结点 s
    将新结点 s 插入到结点 p 之后
    返回 true
bool insertNode(Link head, int i, Data x)  // i 是数据 x 准备插入的位置
{
	p = head; // 工作指针 p 指向头结点
	count = 0;
	while(p!=NULL && count n<i-1)  // 查找到第 i-1 个结点
	{
		p = p->next;
		count ++;
	}
	if(p == NULL)
		return false;
	else
	{
		node = (Link)malloc(sizeof(Node));
		node->data = x;
		node->next = p->next;
		p->next = node;
		return true;
	}
	
}

2.5 创建一个单链表–头插法

头插法:将待插入结点插在头结点的后面
准备一个数组:
在这里插入图片描述
初始化头结点
在这里插入图片描述
算法描述:

head = (Link)malloc(sizeof(Node));
head->next = NULL:

插入第一个元素结点
在这里插入图片描述
算法描述

node = (Link)malloc(sizeof(Node));
node->data = a[0];
node->next = head->next;
head->next = node;

一次插入每一个结点
在这里插入图片描述
算法描述

node = (Link)malloc(sizeof(Node));
node->data = a[1];
node->next = head->next;
head->next = node;

头插法产生的顺序和数组的顺序相反。

头插法

Link newList(Data a[], int n)  // n 是数组元素的个数
{
	// 创建头结点
	head = (Link)malloc(sizeof(Node));
	head->next = NULL;
	// 创建后续结点
	for(i = 0; i<n; i++)
	{
		node = (Link)malloc(sizeof(Node));
		node->data = a[i];
		node->next = head->next;
		head->next = node;
	}
	return head;
}

2.6 创建一个单链表–尾插法

将待插入的结点插在终端结点的后面

初始化
在这里插入图片描述

head = (Link)malloc(sizeof(Node));
head->next = NULL;
rear = head;

插入第一个元素结点
在这里插入图片描述

node = (Link)malloc(sizeof(Node));
node->data = a[0];
rear->next = node;
rear = node;

依次插入每一个结点
在这里插入图片描述

尾插法

 Link newList(Data a[],int n)
 {
 	head = (Link)mallloc(sizeof(Node));  // 生成头结点
 	head->next = NULL;
 	rear = head;   //尾指针初始化
 	for(i = 0; i< n; i++)
 	{
 		node = (Link)malloc(sizeof(Node));
 		node->data = a[i];
 		rear->next = node;
 		rear = node;
 	}
 	rear->next = NULL;
 	return head;
 }

2.7 单链表结点的删除

如何删除 p 所指向的结点?
在这里插入图片描述

q->next = p->next;
free(p);

查找结点过程中,如何保证 p ,q 指针一前一后?
初始化
在这里插入图片描述

p = head->next;
q = head;

移动指针一次
在这里插入图片描述

q = p;
p = p->next;
思路:
在查找过程中,如果发现 p 所指向的结点 data 值不是要找的 x , 
则 p ,q 同时后移,一旦找到,则执行删除操作

没有找到的情况:
在这里插入图片描述

思路:
在查找过程中,如果一直没有找到 data 域为 x 的结点,则进入上面的状态
此时,退出循环,返回 false.

删除时,注意分析边界情况(要删的表尾空表)
在这里插入图片描述

if(head == NULL || head->next == NULL)
	return false;

在这里插入图片描述

bool deleteNode(Link head, Data x)
{
	if(head == NULL || head->next == NULL) // 若链表没有数据
		return false;
	p = head->next;  // 初始化。 p , q 指针一前一后
	q = head;
	while(p!=NULL)
	{
		if(p->data == x)
		{
			q->next = p->next;
			free(p);
			return true;
		}
		else
		{
			q = p;
			p = p->next;
		}
	}
	return false;	
}

2.8 单链表的释放

将单链表中所有结点的存储空间释放
在这里插入图片描述
在这里插入图片描述

q =head;
head = head->next;
free(q);

3. 循环链表的实现

将单链表的首尾相连,将终端结点的指针域由空指针改为指向头结点,构成单循环链表,简称循环链表。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 双向链表

在这里插入图片描述
双向链表:在单链表的每个结点中再设置一个指向其前驱结点的指针域

结点的结构:
在这里插入图片描述

笔记来源
懒猫老师-C语言-链表. 致谢!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一记绝尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值