C语言学习笔记——链表(单链表)

一、关于链表

  • 链表是C语言很重要的一部分。最早开始学链表的时候就没学好,导致后来数据结构的程序也没心思去写。但是这两天既然都闲在家里,闲着也是闲着,不如看看链表,到底是怎么回事。

二、链表的本质

  • 链表是什么呢,其实就是数据的一种存储方式。相对于线性存储,链表是链式存储。它不像数组,每个元素的物理地址是相邻的。链表中每个元素(通常称为节点)的地址是随机的。每当要添加新节点时,链表就要开辟新的空间。即有多少个节点,就开辟多少空间,不会造成空间浪费,这就是链表的优势所在。

三、创建一个新链表

  • 链表中每个节点就是一个结构体,所以我们首先声明一个结构体
typedef struct NODE
{
	int data;
	struct NODE * next;
}Node;
  • 每个节点至少包含两部分,一个称为数据域,用来存放数据。例子中数据域为 int型,也可以是其他类型,包括结构体类型。另一个称为指针域,用来指向下一个节点的地址。如果没有下一个节点则指向NULL。
  • 下面我们来创建一个新的链表。
Node * creatlist()
{
	Node *headNode = (Node*)malloc(sizeof(Node));
	if(headNode == NULL){
		return NULL;
	}
	headNode->data = 0;
	headNode->next = NULL;
	return headNode;
}
int main()
{
	Node *list = creatlist();
	return 0;
}
  • 在main函数中,我们首先定义了一个指向可以Node结构体的指针,然后调用creatlist函数,用该函数的返回值来为list指针初始化。
  • creatlist函数是一个返回类型是Node *的函数,与list类型相同。再看函数里面,首先在堆上开辟空间,定义指针变量 *headNode让其指向新开辟的空间,然后对其进行初始化。最后返回 *headNode。
  • 此时,我们就已经创建了一个新的链表,该链表的第一个节点称为头结点,一般不存放数据。该节点由list指针指向。
void inset( Node *headnode, int data)
{
    Node *newnode = (Node*)malloc(sizeof(Node));
	if(headNode == NULL){
		return NULL;
	}
	newnode->data = data;
	newnode->next = headnode->next;
	headnode->next = newnode;
}
int main()
{
	Node *list = creatlist();
	for (int i = 1; i < 5; i++) {
		inset(list, i);
	}
	return 0;
}
  • 这里我们用头插法向该链表中加入了4个节点,每个节点的数据域分别为 1,2,3,4。下面是添加过程
    首先开辟新的节点,定义*newnode指针指向新开辟的空间,然后将数据放在该空间上,然后把headnode的指针域(NULL)赋值到newnode的指针域,最后让headnode指向新节点。所以按照这个方法,添加顺序是1,2,3,4。但最终结果如果按顺序访问就是4,3,2,1。

四、链表元素的遍历

void show( Node *headnode)
{
	Node *p = headnode->next;
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}
int main()
{
	Node *list = creatlist();
	for (int i = 1; i < 5; i++) {
		inset(list, i);
	}
	show(list);
	return 0;
}

在这里插入图片描述

  • 这里我们已经添加了四个节点,开始遍历链表的每一个元素,当p的不为NULL时,即还有下一个节点,继续输出,直到最后一个节点。

五、链表节点的删除

void delet(Node *p, int data)
{
	Node *p2 = p;
	p = p->next;
	while (p !== NULL && p->data != data) {
		p2 = p;
		p = p->next;
	}
	if (p !== NULL) {
		p2->next = p->next;
		free(p);
	}
	else {
		printf("此数据不存在!\n");
	}
}
int main()
{
	Node *list = creatlist();
	for (int i = 1; i < 5; i++) {
		inset(list, i);
	}
	delet(list,3);
	show(list);
	return 0;
}

在这里插入图片描述

  • 这个函数的作用是删除对应数据的节点。函数内首先创建指针变量p2,p即为链表表头,用来遍历链表,p2用来指向对应数据的前一个节点。当p不为空且数据域不为目标数据时,循环继续,遍历下一个节点。当循环结束时,有两种情况。
  • 第一种是找到了目标数据对应的节点,即p不为NULL,此时,我们将p->next的值赋值给它的上一个节点的next,即让它的上一个节点跳过自己直接指向下一个节点。然后释放目标数据对应节点的空间。
  • 第二种是没有找到目标数据对应的节点,即本链表中没有该数据。那么我们输出“此数据不存在!”。

六、指定位置插入节点

void insert(Node *p, int data) 
{
	Node *p2 = p;
	p = p->next;
	while (p != NULL && p->data > data) {
		p2 = p;
		p = p->next;

	}
	Node *newnode = (Node*)malloc(sizeof(Node));
	if (newnode == NULL) {
		printf("申请空间失败!\n");
	}
	else {
		newnode->data = data;
		newnode->next = p2->next;
		p2->next = newnode;
	}
}
int main()
{
	Node *list = creatlist();
	for (int i = 1; i < 5; i++) {
		inset(list, i);
	}
	delet(list,3);
	show(list);
	insert(list, 3);
	show(list);
	system("pause");
	return 0;
}

在这里插入图片描述

  • 前面我们已经将数据3所对应的节点删除,现在我们将它重新插入进去。
  • 和删除函数一样,p2的作用依然是指向目标节点的前一个节点。创建while循环,我们希望它按顺序大小插入,即当循环结束时,p指向数据2所对应的节点,p2指向数据4所对应的节点。我们要做的就是在这两个之间插入一个新的节点。
  • 申请空间,将目标数据放进新节点得数据域,然后让新节点的指针域指向数据2所对应的节点,最后让数据4所对应的节点的指针域再指向新节点,插入就完成了。

七、本篇博客完整代码

#include <stdio.h>
#include <stdlib.h>
typedef struct NODE
{
	int data;
	struct NODE * next;
}Node;
Node * creatlist()
{
	Node *headNode = (Node*)malloc(sizeof(Node));
	headNode->data = 0;
	headNode->next = NULL;
	return headNode;
}
void inset(Node *headnode, int data)
{
	Node *newnode = (Node*)malloc(sizeof(Node));
	newnode->data = data;
	newnode->next = headnode->next;
	headnode->next = newnode;
}
void show(Node *headnode)
{
	Node *p = headnode->next;
	while (p) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}
void delet(Node *p, int data)
{
	Node *p2 = p;
	p = p->next;
	while (p && p->data != data) {
		p2 = p;
		p = p->next;
	}
	if (p) {
		p2->next = p->next;
		free(p);
	}
	else {
		printf("此数据不存在!\n");
	}
}
void insert(Node *p, int data) 
{
	Node *p2 = p;
	p = p->next;
	while (p != NULL && p->data > data) {
		p2 = p;
		p = p->next;

	}
	Node *newnode = (Node*)malloc(sizeof(Node));
	if (newnode == NULL) {
		printf("申请空间失败!\n");
	}
	else {
		newnode->data = data;
		newnode->next = p2->next;
		p2->next = newnode;
	}
}
int main()
{
	Node *list = creatlist();
	for (int i = 1; i < 5; i++) {
		inset(list, i);
	}
	delet(list,3);
	show(list);
	insert(list, 3);
	show(list);
	system("pause");
	return 0;
}

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值