C语言数据结构与算法之单链表

目录
  • 基本概念
  • 读取数据元素
    • 获取第i个结点的数据元素
    • 插入数据元素 
  • 初始化链表
  • 打印链表
  • 顺序表查空
  • 顺序表的删除 
    • 删除第i个结点及其数据元素
    • 情况1:当删除的是第一个元素
    • 情况2:除第一个结点外
    • 完整代码
  • 删除单链表整表
  • 单链表VS顺序表

基本概念

链表的每一个结点中只包含一个指针域

优点 : 储存空间利用高效

举例来说:

typedef struct student{
	int id;		//学生编号
	char* name; //学生名称

	//指向下一结点的指针
	struct Student* pNext;
}Student;

与之相反的是多链表

typedef struct student{
	int id;		//学生编号
	char* name; //学生名称

	//指向下一结点的指针
	struct Student* pNext;
	struct Student* qNext;
}Student;

读取数据元素

获取第i个结点的数据元素

  1. 声明一个结点指针p指向链表的第一个结点a1,初始化j从1开始
  2. 当j < i 时,遍历链表,让p的指针向后移动,不断指向下一个结点,j 累加 1
  3. 当链表末尾 p 为空时,则说明第 i 个元素不存在;否则查找成功,返回结点 p 的数据

 

1.定义数据元素

//定义数据元素
typedef struct student{
	int id;
	char* name;
}ElementType;

2.定义顺序表结构

typedef struct {
	ElementType dates[MAX_SIZE];   //当前顺序表中的数据集合
	int length;					   //当前顺序表中的元素个数

}SeqList;

3.定义链表的结点(包括数据域和指针域)

typedef struct Node {
	ElementType date;  //数据域
	struct Node* node; //指针域,指向下一个结点
}Node;

4.设置头结点

我们在定义链表时,习惯性的会定义头结点,以便统一链表结点的插入和删除操作

typedef struct Linklist {
	Node* next;  //头指针
	int length;
}Linklist;

如果链表有头结点,next就指向头结点,没有就指向第一个结点

链表的长度初始值为0

插入数据元素 

在第i个结点后插入数据元素  

  1. 创建一个空节点,分配内存空间,设置数据元素
  2. 获取第i个结点,设置新结点的后继结点为该结点的后继结点
  3. 设置第i个结点的后继结点为该结点

1.创建空节点并为数据域赋值

	//创建空节点并为数据赋值
	Node* node = (Node*)malloc(sizeof(Node));
    node -> date = element;
    node -> next = NULL;

2.通过循环找到要插入的结点

	for (int i = 1; currNode && i < pos - 1; i++)
	{
		currNode = currNode->next;
	}

3.将结点插入并对接前面的结点

	if (currNode) {
		node->next = currNode->next;
		currNode->next = node;
		linkList->length++;
	}

初始化链表

void InitLinkList(LinkList* linkList, ElementType* dateArrar, int length)
{
	for (int i = 0; i < length; i++) {
		InsertLinkList(linkList, i + 1, dateArrar[i]);
	}
}

打印链表

void PrintLinkList(LinkList* linklist)
{
	Node* node = linklist->next;
	if (!node)
	{
		printf("链表为空!\n");
		linklist->length = 0;
		return 0;
	}
	for (int i = 0; i < linklist->length; i++) {
		printf("%d\t%s\t\n", node->date.id, node->date.name);
        node = node->next;
	}
}

顺序表查空

int IsLinkListEmpty(LinkList* linkList) {

	return linkList->length == 0 ? TRUE : FALSE;

}

顺序表的删除 

删除第i个结点及其数据元素

  1. 获取第i个结点,若该结点不是第一个结点,则获取第i - 1个结点
  2. 将第i -1个结点的后缀结点设为第i个结点的后缀结点
  3. 删除第i个结点,释放内存空间,记录并返回删除数据元素的值

情况1:当删除的是第一个元素

	if (pos == 1)
	{
		node = linkList->next;
		if (node) {
			element = node->date;
			linkList->next = node->next;
			free(node);  //释放被删除的结点
			linkList->length--;
		}
        return element;
	}

情况2:除第一个结点外

  1. 找到要删除的结点和他的前缀结点
  2. 要删除结点的next 赋值给前缀结点
  3. 释放要删除的结点
	Node* preNode; //前缀结点
	node = linkList->next;
	for (int i = 1; node && i < pos; i++)
	{
		preNode = node;
		node = node->next;
	}
	if (node)
	{
		element = node->date;
		preNode->next = node->next;
		free(node);
		linkList->length--;
	}
	return element;

完整代码

ElementType DeleteLinkListElement(LinkList* linkList, int pos)
{
	ElementType element;   //被删除的元素
	element.id = -999;     //赋一个不可能的值,来判断删除是否成功
	Node* node = NULL;

	if (pos == 1)
	{
		node = linkList->next;
		if (node) {
			element = node->date;
			linkList->next = node->next;
			free(node);  //释放被删除的结点
			linkList->length--;
		}
	}

	Node* preNode; //前缀结点
	node = linkList->next;
	for (int i = 1; node && i < pos; i++)
	{
		preNode = node;
		node = node->next;
	}
	if (node)
	{
		element = node->date;
		preNode->next = node->next;
		free(node);
		linkList->length--;
	}
	return element;

}

删除单链表整表

  1. 声明结点p 和 q
  2. 将第一个结点赋值给p
  3. 循环将下一个结点赋值给q,释放p,将q赋值给p

 

void CleatLinkList(LinkList* linkList)
{
	Node* node = linkList->next;
	Node* nextNode;
	while (node) {
		nextNode = node->next;  //先记录当前结点的下一个结点,以便释放当前结点的内存
		free(node);
		node = nextNode;
	}
	linkList->next = NULL;
	linkList->length = 0;
}

单链表VS顺序表

 

 

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

(0)

相关推荐

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

    目录 引言 链表的相关思考 链表结点结构 建立链表 实现插入操作 完整代码 引言 在存储一大波数的时候,我们通常使用的是数组,但是数组有时候又会显得不够灵活,比如下面这个例子: 有一串已经排序好的数 2,3,5,8,9 ,10 如果我们想要往数组中插入6 这个元素,需要把 8 以后的元素全部往后挪一位 这样操作显然很耗费时间,如果使用链表的话则会快很多.那么什么是链表呢?请看下图: 此时如果需要在8前面加入一个6,那么只需要向下图一样更改一下就可以了,而不用向像最开始那样把每个数向后挪. 链表的

  • C语言数据结构之顺序表和单链表

    一.顺序表的创建.删除和插入 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> struct sqlist { int date[10]; int length; }; void InitList(sqlist& L) { for (int i = 0;i < 10;i++) { L.date[i] = 0; } L.length = 0; } void charu(sqlist& L) { for (int j =

  • 数据结构 C语言实现循环单链表的实例

    数据结构 C语言实现循环单链表的实例 实例代码: //=========杨鑫========================// //循环单链表的实现 #include <stdio.h> #include <stdlib.h> typedef int ElemType; //定义结点类型 typedef struct Node { ElemType data; struct Node *next; }Node,*LinkedList; int count = 0; //1.单循环

  • C语言数据结构单链表接口函数全面讲解教程

    目录 前言 一.链表的概念及结构 1.概念 二.链表的使用 1.遍历整个链表 2.尾插 3.头插 4.头删 5.尾删 6.任意位置插入数据 7.任意位置删除数据 后记 前言 上一期数据结构专栏我们学习了顺序表后:C语言数据结构顺序表 在运用时,细心的同学可能会发现,如果要头插.尾插或者任意位置.如果原先的空间已经被占满了,你是需要扩容的,动态链表扩容往往是2倍,但是扩容后,如果后面没有使用完全扩容后空间就会造成空间浪费,为了解决这个问题,我们今天将学习链表. 提示:以下是本篇文章正文内容,下面案

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

    目录 引入 模拟链表介绍 插入代码实现 代码实现   引入 在上一节的学习中我们介绍了C语言如何实现链表,但是,在这一章,我们将抛开令人头秃的指针和结构体,我们将另外使用一种数组来实现的方式,叫做模拟链表.让我们一起来看看. 模拟链表介绍 链表中的每一个结点都只有两个部分. 我们可以使用一个数组date来储存每序列中的每一个数.那每一个数右边的数是谁,这一点该如何解决呢?在上一章的内容中我们是使用指针来解决的,这里我们只需再用一个数组right来存放序列中每一个数右边的数是谁就可以了.具体要怎么

  • C语言创建和操作单链表数据结构的实例教程

    1,为什么要用到链表 数组作为存放同类数据的集合,给我们在程序设计时带来很多的方便,增加了灵活性.但数组也同样存在一些弊病.如数组的大小在定义时要事先规定,不能在程序中进行调整,这样一来,在程序设计中针对不同问题有时需要3 0个大小的数组,有时需要5 0个数组的大小,难于统一.我们只能够根据可能的最大需求来定义数组,常常会造成一定存储空间的浪费. 我们希望构造动态的数组,随时可以调整数组的大小,以满足不同问题的需要.链表就是我们需要的动态数组.它是在程序的执行过程中根据需要有数据存储就向系统要求

  • C语言数据结构与算法之单链表

    目录 基本概念 读取数据元素 获取第i个结点的数据元素 插入数据元素  初始化链表 打印链表 顺序表查空 顺序表的删除  删除第i个结点及其数据元素 情况1:当删除的是第一个元素 情况2:除第一个结点外 完整代码 删除单链表整表 单链表VS顺序表 基本概念 链表的每一个结点中只包含一个指针域 优点 : 储存空间利用高效 举例来说: typedef struct student{ int id; //学生编号 char* name; //学生名称 //指向下一结点的指针 struct Studen

  • Java数据结构与算法之单链表深入理解

    目录 一.单链表(Linked List)简介 二.单链表的各种操作 1.单链表的创建和遍历 2.单链表的按顺序插入节点 以及节点的修改 3.单链表节点的删除 4.以上单链表操作的代码实现 (通过一个实例应用) 三.单链表常见面试题 1.求单链表中节点的个数 2.查找单链表中的倒数第K个节点[新浪面试题] 3.单链表的反转[腾讯面试题,有点难度] 4.从尾到头打印单链表 一.单链表(Linked List)简介 二.单链表的各种操作 1.单链表的创建和遍历 2.单链表的按顺序插入节点 以及节点的

  • C语言数据结构创建及遍历十字链表

    目录 一.十字链表是什么? 二.十字链表的存储结构 三.代码实现 1.引入头文件并定义结构体 2.建立十字链表 3.遍历十字链表 4.调用函数 本文需要读者有一定的代码基础,了解指针,链表,数组相关知识. 一.十字链表是什么? 十字链表常用于表示稀疏矩阵,可视作稀疏矩阵的一种链式表示,因此,这里以稀疏矩阵为背景介绍十字链表.不过,十字链表的应用远不止稀疏矩阵,一切具有正交关系的结构,都可用十字链表存储. 二.十字链表的存储结构 1.用于总结点的存储结构 m:总行数 n:总列数 len:总元素个数

  • C语言数据结构与算法之时间空间复杂度入门

    目录 数据结构与算法 什么是数据结构?什么是算法? 分析维度 大O的渐进表示法 常数阶 线性阶 对数阶 其他时间复杂度指标 空间复杂度 数据结构与算法 终于开始搞这块难啃的骨头了,走上这条漫漫长路之前要明白: 什么是数据结构?什么是算法? 是数据之间存在一种或多种特定关系的数据元素集合,为编写出一个“好”的程序,必须分析待处理对象的特性及各处理对象之间存在的关系,这也就是研究数据结构的意义所在为编写出一个“好”的程序,必须分析待处理对象的特性及各处理对象之间存在的关系这也就是研究数据结构的意义所

  • C语言数据结构超详细讲解单向链表

    目录 1.链表概况 1.1 链表的概念及结构 1.2 链表的分类 2. 单向链表的实现 2.1 SList.h(头文件的汇总,函数的声明) 2.2 SList.c(函数的具体实现逻辑) 2.2.1 打印链表 2.2.2 搞出一个新节点(为其他函数服务) 2.2.3 链表尾插 2.2.4 链表头插 2.2.5 链表尾删 2.2.6 链表头删 2.2.7 查找节点 2.2.8 在pos位置之前插入 2.2.9 在pos位置之后插入 2.2.10 删除pos位置 2.2.11 删除pos之后位置 2.

  • C语言 超详细模拟实现单链表的基本操作建议收藏

    目录 1 链表的概念及结构 2 链表的分类 3 链表的实现无头+单向+非循环链表增删查改实现 3.1 链表的定义 3.2 链表数据的打印 3.3 链表的尾插 3.4 链表空间的动态申请 3.5 链表的头插 3.6 链表的尾删 3.7 链表的头删 3.8 链表任意位置的前插入 3.9 链表任意位置的后插入 3.10 链表的任意位置的删除 3.11 链表的任意位置的前删除 3.12 链表的任意位置的后删除 3.13 链表的销毁 3.14 链表的总结 1 链表的概念及结构 概念:链表是一种物理存储结构

  • C语言 超详细模拟实现单链表的基本操作建议收藏

    目录 1 链表的概念及结构 2 链表的分类 3 链表的实现无头+单向+非循环链表增删查改实现 3.1 链表的定义 3.2 链表数据的打印 3.3 链表的尾插 3.4 链表空间的动态申请 3.5 链表的头插 3.6 链表的尾删 3.7 链表的头删 3.8 链表任意位置的前插入 3.9 链表任意位置的后插入 3.10 链表的任意位置的删除 3.11 链表的任意位置的前删除 3.12 链表的任意位置的后删除 3.13 链表的销毁 3.14 链表的总结 1 链表的概念及结构 概念:链表是一种物理存储结构

  • C++数据结构与算法之反转链表的方法详解

    本文实例讲述了C++数据结构与算法之反转链表的方法.分享给大家供大家参考,具体如下: 算法概述:要求实现将一条单向链表反转并考虑时间复杂度. 算法分析: 数组法(略): 将列表元素逐个保存进数组,之后再逆向重建列表 点评:实现逻辑最简单,需要额外的内存开销. 移动指针: 通过三个指针逐个从链表头开始逐一反转链表元素的指针 点评:不需要额外的内存开销,会改变原始链表. 递归: 以递归的方式首先找到链表尾部,再逐一反转指针 点评:不需要额外的内存开销,不会改变原始链表. 算法实现: 构建链表结构 /

随机推荐