链表(C语言)

前言

本次我们介绍链表的创建及增,删,改,及反转。

一、链表是什么?

首先我们来了解一下线性存储结构。线性存储结构是一种最常见的存储结构。其特点是数据元素之间存在一一对应的关系。线性存储结构又分为两种,即顺序存储结构链式存储结构
1.首先,我们来了解一下顺序存储结构。顺序存储的线性表称为顺序表(数组)。其原理是逻辑上相邻的元素在物理位置上也相邻。
我们可以理解为一堆按照一定顺序摆放的书。我们在知道它的排列规律之后就可以通过它的排列规律来找到我们想找到的那本书。我们也可以通过一本一本的去找,来找到我们想要找到的那本书。
我们可以很方便的理解,要在这一堆有顺序的书中放进去一本或者拿出来一本,我们必然要先找到要它的位置在进行操作,而且我们需要一个连续的地方来放这一堆书。

2.其次,我们来了解一下链式存储结构(链表)。它的特点是逻辑上不相邻的两个元素在物理位置上也相邻。我们可以理解为有一本书,这本书在你打开它之后会看到它本身的内容,也会得到第二本书所在的地址。你可以通过这个地址来寻找第二本书。
不难理解,如果我们要在这组书中加入一本书,只需要在某一本书后边加上这本书所在的地址,在在这本书后边加上原本那本书后边的地址即可。而且我们并不需要一块很大的连续的空间来存放这堆书。

链表是一种类似于数组又不同于数组的一种线性表。
在这里插入图片描述

二、单链表的初识

在这里插入图片描述

1.定义结构体

注意要包含头文件
#include<stdlib.h>

struct Node {
	int data;
	struct Node* next;
};

2.创建头节点

struct Node* CreatList () {
	struct Node* HeadNode = (struct Node*)malloc(sizeof(struct Node));
	//给HeadNode申请了一块大小为struct Node的空间,将它强制类型转换为struct Node*
	HeadNode->data = 1;
	//初始化HeadNode的值
	HeadNode->next = NULL;
	//置空HeadNode的下一个结构体变量
	return HeadNode;
}

3.写一个函数,用来创建结点

struct Node* CreatNode(int data) {
	struct Node* NewNode = (struct Node*)malloc(sizeof(struct Node));
	NewNode->data = data;
	//将要输入的数据存放到新节点中
	NewNode->next = NULL;
	//将新节点的next置空
	return NewNode;
}

4.头插法插入新结点

void InsertNodeByHead(struct Node* HeadNode, int data) {
	struct Node* NewNode = CreatNode(data);
	//调用函数创建节点
	NewNode->next = HeadNode->next;
	//新节点指向原来头结点的next
	HeadNode->next = NewNode;
	//原来的头结点的next指向新节点
}

}

在这里插入图片描述

5.尾插法插入新结点

void InsertNodeByTrall(struct Node* HeadNode, int data) {
	struct Node* NewNode = CreatNode(data);
	//同样使用函数创建一个新节点
	while (HeadNode->next) {
		HeadNode = HeadNode->next;
		//次循环用于找到链表的尾节点
	}
	HeadNode->next = NewNode;
	//此时的HeadNode即为尾节点,要使用尾插法即在HeadNode之后添加新节点
	NewNode->next = NULL;
	//此时的新节点即为链表的尾,置空它
}

在这里插入图片描述

6.删除指定节点

void DeleteNode(struct Node* HeadNode, int Deletedata) {
	struct Node* DeleteNode = HeadNode->next;
	struct Node* DeleteNodeFront = HeadNode;
	if (HeadNode->next == NULL) {
		printf("链表为空,删除失败");
		//如果头结点的next为空则说明链表为空,不可能存在要删除的节点
	} else {
		if (DeleteNode->data != Deletedata) {
			DeleteNode = DeleteNode->next;
			DeleteNodeFront = DeleteNodeFront->next;
		} else {
			DeleteNode = HeadNode->next;
			//此部分用于找到要删除的结点
		}
	}
	DeleteNodeFront->next = DeleteNode->next;
	//此时结点被删除
	free(DeleteNode);
	//free被删除的结点
}

在这里插入图片描述

7.打印节点

void PrintNode(struct Node* HeadNode) {
	while (HeadNode->next != NULL) {
		printf("%d ", HeadNode->next->data);
		HeadNode = HeadNode->next;
		//遍历链表,依次打印
	}
	printf("\n");
}

8.修改节点

void ChangeNode(struct Node* HeadNode, int data, int Changedata) {
	struct Node* ChangeNode = HeadNode->next;
	if (ChangeNode == NULL) {
	//如果HeadNode的next为空,则说明链表为空,不可能存在要修改的结点
		printf("链表为空,修改失败");
	} else {
		if (ChangeNode->data != data) {
			ChangeNode = ChangeNode->next;
			//找到要修改的数值对应的结点
		} else {
			ChangeNode->data = Changedata;
			//修改这个数值
		}
	}
}

9.反转链表

本次介绍反转链表中很常见的一种方法,三指针依次迭代

void ReverseList(struct Node* HeadNode) {
	struct Node* p = HeadNode->next;
	struct Node* q = p->next;
	struct Node* r = NULL;
	p->next = NULL;
	while (q) {
		r = q;
		q = r->next;
		r->next = p;
		p = r;
	}
	HeadNode->next = r;
	return HeadNode;
}

10.按顺序插入节点

void InserNodeByOrder(struct Node* HeadNode,int Insertdata) {
	struct Node* NewNode = CreatNode(Insertdata);
	struct Node* p = HeadNode->next;
	struct Node* q = p->next;
	if (p==NULL) {
		p = NewNode;
		NewNode->next = NULL;
	} while (p) {
		if ( (p->data<Insertdata) && (q->data>Insertdata) ) {
			p->next = NewNode;
			NewNode->next = q;
			break;
		} else {
			p = p->next;
			q = q->next;
		}
	}
}

三、应用

int main() {
	struct Node* List = CreatList();//先创建一个链表
	InsertNodeByHead(List, 1);
	InsertNodeByHead(List, 2);
	InsertNodeByHead(List, 3);//头插法依次插入1,2,3
	PrintNode(List);
	InsertNodeByTrall(List, 9);//尾插法插入9
	PrintNode(List);
	DeleteNode(List, 3);//删除链表中数值为3的结点
	PrintNode(List);
	ChangeNode(List, 2, 4);//将链表中数值为2的结点的数值改为4
	PrintNode(List);
}

在这里插入图片描述
第一个321表示使用头插法插入的123
然后的3219表示使用尾插法插入了9
219表式删除了3
419表示将2替换为4

  • 13
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

山河丘壑

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

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

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

打赏作者

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

抵扣说明:

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

余额充值