手把手教你:单链表的创建,以及各种插法、删法(基于C语言)(其一)

前置知识:C语言基础语法,指针,结构体,动态内存申请

         前言:链表作为一种非常基础的数据结构,在C程序当中也是应用广泛(比如大学生作业要做的管理系统)。链表就像是一辆火车,而每一个节点就是火车的车厢,所以大家学习链表的时候不妨把链表就当作是一辆火车去看待,方便想象。

请细心阅读每一个字并记住上下文(我也会适当的提醒滴)

一个单链表最主要包含两个部分:数据域 和 指针域

数据域:即为各种数据,可以是int、char等基础数据类型,也可以是结构体等的自定义数据类型

指针域:用于指向下一个节点的指针,链表就是通过指针来把各个节点连接到一起,形成一个有逻辑的顺序表。

为了方便,这里就不用结构体作为数据了,直接用一个int类型作为链表的数据域

单链表的设计:

#include <stdio.h>        //这里的头文件下面的代码中会用上,所以一起写上了
#include <stdlib.h>
#include <assert.h>

typedef struct Node
{
	int data;
	struct Node* next;
}Node, List;

        如上图所示,这里我们设计的链表由一个int data作为数据域。而Node* next作为指向下一节点的指针。至于为什么要起一个别名叫做List呢?请接着往下看(如果不知道typedef在结构体中的作用可以去搜一下哦)

接下来就到了单链表的创建了

        我们知道,一辆火车最主要的就是火车头,通过火车头才能把后面的车厢连接起来,才能群龙有首,火车头一般是不用来装货物的,装货物的一般是车厢。因此我这里起了个别名叫做List,来表示List节点就代表了头节点,即火车头。而Node用来代表装数据用的车厢。

链表的创建:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef struct Node
{
	int data;
	struct Node* next;
}Node, List;


List* createList()
{
	List* list = (List*)calloc(1, sizeof(List));
	assert(list);
	return list;
}

int main()
{
    List* list = createList();    //创建一个链表

    return 0;
}

有人可能会有疑问,为啥要把创建一个链表封装成一个函数捏?还有为啥List* list = createList();就相当于创建了一个链表捏?

回答1:封装成一个函数是为了简便,而且通过调用这个函数,我们可以快速的创建多个链表,就不用复制粘贴前面的代码了。

回答2:前面说到了,一节火车最重要的就是火车头,而有了火车头,后面的节点,我们只要用指针连接上去就行了,所以,这其实就相当于创建了一个链表,只是火车头的后面目前还没有车厢而已。

节点的创建:

        请移步到 Node* createNode(int data)这个函数

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef struct Node
{
	int data;
	struct Node* next;
}Node, List;


List* createList()
{
	List* list = (List*)calloc(1, sizeof(List));
	assert(list);
	return list;
}

Node* createNode(int data)
{
	Node* newNode = (Node*)calloc(1, sizeof(Node));
	assert(newNode);
	newNode->data = data;
	return newNode;
}

        同样为了后续插入数据的代码的简便,这里createNode函数封装的创建节点的过程,这里传入的参数int data,则代表了这个节点存储的数据。

---------------------------------------------------------------------------------------------------------------------------------

那么接下来就到了重头戏,也就是链表的插入、删除、展示。

链表的插入:

尾插法:

尾插法,顾名思义,就是在链表的最后面插入节点。即在一辆火车的后面,接入新的车厢。这里我们需要先知道一件事情,一个单链表的尾节点的指向总是指向NULL的。这个很好理解,因为火车尾的后面也是没有车厢的,尾部接的是空气嘛。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

//为了避免代码太长了,所以省略的前面的代码

void push_back(List* list, int data)
{
	Node* newNode = createNode(data);
	Node* curNode = list;
	while (curNode->next != NULL)
	{
		curNode = curNode->next;
	}
	curNode->next = newNode;
}

这里我们分步骤给大家逐一讲解:

  1. push_back函数的参数指明了我们需要插入到哪个链表,以及需要插入的数据是什么。
  2. 在函数体当中,我们先是调用了createNode函数,来创建了一个需要插入的节点,newNode即为需要插入的节点。
  3. 然后,既然是尾插法,那么我们就需要先找到链表的尾部,即找到火车最后的一节车厢。(注意,当链表只有头节点的时候,那么这个时候头节点 == 尾节点)
  4. 我们用创建了一个Node*的指针curNode,代表的是当前节点。我们前面说过,尾节点是肯定指向空的,根据这个特性,我们可以很容易的找到尾节点,因此while循环里面的条件即为curNode->next != NULL
  5. 可能很多人看到curNode = curNode->next就一脸懵逼了,不懂是什么意思,这里curNode是代表当前遍历到的节点,而curNode->next代表的是下一个节点嘛。那么curNode = curNode->next,就相当于我们让 当前节点 = 下一个节点 这样我们不就实现了遍历每一个节点了嘛。因为curNode = curNode->next 是放在while循环当中的,curNode和curNode->next都是在不停的变化的。你只要记住:curNode->next 永远表示的是当前节点的下一个节点就行了。
  6. 最后,当循环结束了,curNode就变成了尾节点了,然后让curNode指向newNode(curNode->next = newNode),至此链表连接成功。

由于篇幅原因,接下来的头插法、任意插法,节点的删除等会在后面的文章写上,可以查看数据结构专栏哦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值