C语言数据结构与算法之链表(一)

 更新时间:2021年12月13日 14:09:23   作者:玄澈_  
链表是线性表的链式存储方式。链表的内存是不连续的,前一个元素存储地址的下一个地址中存储的不一定是下一个元素。小编今天就将带大家深入了解一下链表,快来学习吧

引言

在存储一大波数的时候,我们通常使用的是数组,但是数组有时候又会显得不够灵活,比如下面这个例子:

有一串已经排序好的数 2,3,5,8,9 ,10

如果我们想要往数组中插入6 这个元素,需要把 8 以后的元素全部往后挪一位

这样操作显然很耗费时间,如果使用链表的话则会快很多。那么什么是链表呢?请看下图:

此时如果需要在8前面加入一个6,那么只需要向下图一样更改一下就可以了,而不用向像最开始那样把每个数向后挪。

链表的相关思考

为了实现链表这样的数据结构,我们需要使用指针和malloc这样的函数。

注意 : malloc 函数的返回值是 void * 类型,我们需要对其进行强制类型转换 

使用malloc时需要调用头文件 <stdlib.h>

为什么我们要用这么复杂的办法来储存类型呢?

因为按照之前的方法,我们必须预先准确地知道所需变量的个数,也就是说我们必须我们必须定义出所有的变量。假如说你现在定义了100个变量,而实际上则需要101个变量,那么就不得不对这个程序进行修改。

而有了malloc函数,我们可以在程序运行的过程中根据实际情况来申请空间。

链表结点结构

每一个结点都由两个部分组成。左边的部分用来存放具体的值,那么用一个整型变量就可以;右边的部分则需要储存下一个点的地址,则可以用指针来实现(也称为后继指针)。

这里我们定义一个结构体类型来存储这个结点:

struct node
{
	int date;
	struct node* next;
};

因为下一个结点的类型也是 struct node ,所以我们指针的类型也必须是 struct node * 类型。

建立链表

首先,我们需要一个头指针 head 指向链表的最开始。当链表还没有建立的时候头指针head为空(也可以理解指向空结点)。

struct node* head;
head = NULL;  //头指针初始为空

现在,我们来创立第一个结点,并用临时指针p指向这个结点

struct node* p;
//动态申请一块空间,用来存放一个结点,并用临时指针p指向这个结点
p = (struct node*)malloc(sizeof(struct node));

接下来分别设置新建的结点的左半部分和右半部分

scanf("%d", &a);
p->date = a;	 //将数据存储到当前结点的date域中
p->next = NULL;  //设置当前结点的后继指针为空,也就是当前结点的下一个结点为空

下面来设置头指针并设置新创结点的 *next 指向空 。头指针的作用是方便以后从头遍历整个链表

if (head == NULL)
	head = p;  //如果这是第一个创建的结点,则将头指针指向这个结点
else
	q->next = p;	//如果不是第一个创建的结点,则将上一个结点的后继指针指向当前结点

如果是第一个创立的结点,则将头指针指向这个结点 

如果不是第一个创建的结点,则将上一个结点的后继节点指向当前结点。

最后要将指针q也指向当前结点,因为待会临时指针p将会指向新创建的结点。

q = p;  //指针q也要指向当前结点
#include <stdio.h>
#include <stdlib.h>
 
//这里创建一个结构体用来表示链表的结点类型
struct node
{
	int date;
	struct node* next;
};
 
int main()
{
	struct node* head, * p, * q = NULL, * t;
	int i, n, a;
	scanf("%d", &n);
	head = NULL;  //头指针初始化为空
	for (i = 1; i <= n; i++)
	{
		scanf("%d", &a);
		//动态申请一块空间,用来存放一个结点,并用临时指针p指向这个结点
		p = (struct node*)malloc(sizeof(struct node));
		p->date = a;
		p->next = NULL; //设置当前结点的后继指针为空,也就是下一个结点为空
		if (head == NULL)
			head = p;	//如果这是第一个创建的结点,则将头指针指向这个点
		else
			q->next = p;//如果不是第一个创建的结点,则将上一个结点的后继节点指向当前结点
 
		q = p;  //指针q也指向当前结点
	}
 
	//输出链表中的所有数
	t = head;
	while (t != NULL)
	{
		printf("%d  ", t->date);
		t = t->next;  //继续下一个结点
	}
 
}

效果图

实现插入操作

首先用一个临时指针t从链表的头部开始遍历

 t = head; //从链表的头部开始遍历

等到指针t的下一个结点的值比6大的时候,将6插到中间。

即 t -> next -> date 大于 6 的时候进行插入

代码实现

	scanf("%d", &a);  //读入待插入的数
	t = head;		  //从链表的头部开始遍历
	while (t != NULL)
	{
		if (t->next->date > a || t->next->next == NULL)
		{
			//如果当前结点是最后一个结点或者下一个结点的值大于待插入的值的时候插入
			p = (struct node*)malloc(sizeof(struct node)); //申请一块空间,来存放新增结点
			p->date = a;
			p->next = t->next;//新增结点的后继指针指向当前结点的后继指针所指向的结点
			t->next = p;	  //当前结点的后继指针指向新增结点
			break;			  //插入完毕退出循环
			 
		}
		t = t->next;   //继续下一个结点
	}

完整代码

效果图:

#include <stdio.h>
#include <stdlib.h>
 
//这里创建一个结构体用来表示链表的结点类型
struct node
{
	int date;
	struct node* next;
};
 
int main()
{
	struct node* head, * p, * q = NULL, * t;
	int i, n, a;
	scanf("%d", &n);
	head = NULL;  //头指针初始化为空
	for (i = 1; i <= n; i++)
	{
		scanf("%d", &a);
		//动态申请一块空间,用来存放一个结点,并用临时指针p指向这个结点
		p = (struct node*)malloc(sizeof(struct node));
		p->date = a;
		p->next = NULL; //设置当前结点的后继指针为空,也就是下一个结点为空
		if (head == NULL)
			head = p;	//如果这是第一个创建的结点,则将头指针指向这个点
		else
			q->next = p;//如果不是第一个创建的结点,则将上一个结点的后继节点指向当前结点
 
		q = p;  //指针q也指向当前结点
	}
 
	scanf("%d", &a);  //读入待插入的数
	t = head;		  //从链表的头部开始遍历
	while (t != NULL)
	{
		if (t->next->date > a || t->next->next == NULL)
		{
			//如果当前结点是最后一个结点或者下一个结点的值大于待插入的值的时候插入
			p = (struct node*)malloc(sizeof(struct node)); //申请一块空间,来存放新增结点
			p->date = a;
			p->next = t->next;//新增结点的后继指针指向当前结点的后继指针所指向的结点
			t->next = p;	  //当前结点的后继指针指向新增结点
			break;			  //插入完毕退出循环
			 
		}
		t = t->next;   //继续下一个结点
	}
 
 
 
 
	//输出链表中的所有数
	t = head;
	while (t != NULL)
	{
		printf("%d  ", t->date);
		t = t->next;  //继续下一个结点
	}
 
}

以上就是C语言数据结构与算法之链表(一)的详细内容,更多关于C语言数据结构 链表的资料请关注脚本之家其它相关文章!

相关文章

  • C++单例模式的懒汉模式和饿汉模式详解

    C++单例模式的懒汉模式和饿汉模式详解

    这篇文章主要为大家详细介绍了C++懒汉模式和饿汉模式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • C语言解线性方程的四种方法

    C语言解线性方程的四种方法

    这篇文章主要介绍了C语言解线性方程的四种方法,大家参考使用,学习线性代数的同学一定能用到
    2013-11-11
  • 一文掌握C++ const与constexpr及区别

    一文掌握C++ const与constexpr及区别

    C++ 11标准中,const 用于为修饰的变量添加“只读”属性而 constexpr关键字则用于指明其后是一个常量,编译器在编译程序时可以顺带将其结果计算出来,而无需等到程序运行阶段,这样的优化极大地提高了程序的执行效率,本文重点介绍C++ const与constexpr区别介绍,一起看看吧
    2024-02-02
  • C语言简明清晰讲解枚举

    C语言简明清晰讲解枚举

    枚举法的本质就是从所有候选答案中去搜索正确的解,枚举算法简单粗暴,他暴力的枚举所有可能,尽可能地尝试所有的方法,感兴趣的朋友来看看吧
    2022-05-05
  • 仿写C语言string.h头文件检验字符串函数

    仿写C语言string.h头文件检验字符串函数

    这里给大家分享的是一个C语言string.h头文件检验字符串函数的仿写,非常的简单实用,小编觉得这篇文写的还不错,希望能够给你带来帮助
    2021-11-11
  • C++ LeetCode1827题解最少操作使数组递增

    C++ LeetCode1827题解最少操作使数组递增

    这篇文章主要为大家介绍了C++ LeetCode1827题解最少操作使数组递增示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • C++数据结构之实现邻接表与邻接矩阵的相互转换

    C++数据结构之实现邻接表与邻接矩阵的相互转换

    这篇文章主要为大家学习介绍了C++如何实现邻接表与邻接矩阵的相互转换,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-07-07
  • C++动态规划中关于背包问题讲解

    C++动态规划中关于背包问题讲解

    可能有些读者有接触过动态规划,可能也有一些读者以前完全不知道动态规划这个东西,别担心,我这篇文章会为读者做一个入门,好让读者掌握这个重要的知识点
    2023-03-03
  • 关于移位操作的一点重要说明

    关于移位操作的一点重要说明

    下面小编就为大家带来一篇关于移位操作的一点重要说明。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • C语言之结构体定义 typedef struct 用法详解和用法小结

    C语言之结构体定义 typedef struct 用法详解和用法小结

    这篇文章主要介绍了C语言的结构体定义typedef struct用法详解和用法小结,typedef是类型定义,typedef struct 是为了使用这个结构体方便,感兴趣的同学可以参考阅读
    2023-03-03

最新评论