广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言实现无头单链表详解
  • 512
分享到

C语言实现无头单链表详解

2024-04-02 19:04:59 512人浏览 泡泡鱼
摘要

目录链表的结构体描述(节点)再定义一个结构体(链表) 断言处理 & 判空处理创建链表创建节点头插法打印链表尾插法 指定位置插入 头删法尾删法&n

再封装的方式,用 c++ 的思想做无头链表

链表的结构体描述(节点)

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>       
typedef int DataType;
//节点
typedef struct node        
{
	DataType data;
	struct Node* next;
}NODE,*LPNODE;

再定义一个结构体(链表) 

通过记录头节点和尾节点的方式去描述链表

typedef struct list 
{
	LPNODE frontNode;        //头节点
	LPNODE backNode;         //尾节点
	int curSize;	         //当前节点个数
}LIST,*LPLIST;

断言处理 & 判空处理

如果 list 为空,会引发中断(申请内存可能失败)

防御性编程,如果申请内存失败,操作无效,NULL 里面没有 frontNode,backNode,curSize,存在安全隐患C6011:取消对 NULL 指针"list"的引用

如果申请内存失败,assert()直接让程序直接中断,并且告诉你程序断在哪一行

#include<assert>    //断言处理宏
   #define assert(expression) (void)(  \
            (!!(expression)) ||        \
(_wassert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0) \
        )
 
LPLIST  createList() 
{
	LPLIST list = (LPLIST)malloc(sizeof(LIST)); 
    list = NULL;                        //list为空 引发中断
	assert(list);		           
    //if(list == NULL)
    //return NULL;                      //可以替换
	list->frontNode = NULL;                     
	list->backNode = NULL;
	list->curSize = 0;                         
	return list;
}
 
//abort() has been called line 25

创建链表

描述链表最初的状态

LPLIST  createList() 
{
	LPLIST list = (LPLIST)malloc(sizeof(LIST)); //用结构体变量去描述 做动态内存申请
	assert(list);		                   
	list->frontNode = NULL;                     //链表刚开始是空的 头尾节点指向空
	list->backNode = NULL;
	list->curSize = 0;                          //当前元素个数为0
	return list;
}

创建节点

LPNODE createNode(int data) 
{
	LPNODE newNode = (LPNODE)malloc(sizeof(NODE));
	assert(newNode);
    //初始化数据
	newNode->data = data;
	newNode->next = NULL;
	return newNode;
}

头插法

插入一个节点,节点插在原表头前面,表头会改变,在1(表头)前面插入666(数据)

把新节点的 next 指针指向原来的表头

把原来表头指针从原来的位置挪到新节点的位置

//插入的链表 插入的数据
void push_front(LPLIST list,int data) 
{
	LPNODE newNode = createNode(data);    //创建新节点
	newNode->next = list->frontNode;
	list->frontNode = newNode;
	//护头也要护尾
	if (list->curSize == 0)               //只有一个节点 链表为空尾节点也是指向新节点
		list->backNode = newNode;         //把尾节点置为新节点
	list->curSize++;
}
//测试代码
	LPLIST list = createList();
	push_front(list, 1);
	push_front(list, 2);                  //2 1
	printList(list);                      

打印链表

从第1个节点开始打印

void printList(LPLIST list) 
{
	LPNODE pmove = list->frontNode;
	while (pmove != NULL)             //不为空打印数据
	{
		printf("%d\t", pmove->data);   
		pmove = pmove->next;
	}
	printf("\n");
}

尾插法 

不需要找尾巴,因为记录了尾巴的位置

//插入的链表 插入的数据
void push_back(LPLIST list, int data) 
{
	LPNODE newNode = createNode(data);     //创建新节点
	if (list->curSize == 0) 
	{
		list->frontNode = newNode;         //只有1个节点的情况 表头也是指向新节点
		//list->backNode = newNode;        //表尾指向新节点
	}	
	else 
	{
		list->backNode->next = newNode;    //把原来链表的尾节点的next指针置为新节点
		//list->backNode = newNode;        //原来的表尾挪到新节点的位置
	}
	list->backNode = newNode;              //相同代码
	list->curSize++;
}
//测试代码
    push_back(list, 666);
	push_back(list, 999);                  //2 1 666 999
	printList(list);

指定位置插入 

根据指定数据做插入,插在指定位置(数据)前面,不需要考虑表尾(尾插)

分改变表头、不改变表头两种情况:指定数据,数据可能插在表头前面(头节点的数据==指定数据)

前驱节点的 next 指针指向新节点,新节点的 next 指针指向当前节点

void push_appoin(LPLIST list, int posData, int data) 
{
	if (list == NULL || list->curSize == 0)  //为空无法做插入
	{
		printf("无法插入链表为空!\n");
		return;
	}
    //其他情况可以插入
	if (list->frontNode->data == posData)    //头节点的数据==指定数据 
	{
		push_front(list, data);              //会改变表头 用头插法插入
		return;
	}
    //正常插入的情况
	LPNODE preNode = list->frontNode;        //定义一个前驱节点指向第1个节点
	LPNODE curNode = list->frontNode->next;  //定义一个当前节点指向第1个节点的下一个节点
    //当前节点!=NULL && 当前节点的数据!=指定数据
	while (curNode != NULL && curNode->data != posData) //并排往下走
	{
		preNode = curNode;                   //前1个节点走到当前节点的位置
		curNode = preNode->next;             //当前节点走到原来位置的下一个
	}
    //分析查找结果做插入
	if (curNode == NULL)                     //没找到无法做插入
	{
		printf("没有找到指定位置,无法插入!\n");
	}
	else 
	{
		LPNODE newNode = createNode(data);   //创建新节点 
		preNode->next = newNode;             //连接
		newNode->next = curNode;             
		list->curSize++;
	}
}
//测试代码
    push_appoin(list, 666, 888);
	printList(list);                         //2 1 888 666 999

头删法

只有一个节点的情况:表尾也要改变(表尾指向了一段删除的内存),表尾也要置为空

void pop_front(LPLIST list)
{
	if (list == NULL || list->curSize == 0)     //判空处理
	{
		printf("链表为空,无法删除!\n");
		return;
	}
	LPNODE nextNode = list->frontNode->next;    //头节点的下一个--->第2个节点
	free(list->frontNode);                      //直接删除表头
	list->frontNode = nextNode;                 //把原来的表头节点置为下一个节点
	if (list->curSize == 1)                     //只有1个节点的情况
	{
		list->backNode = NULL;                  //表尾也要置为空
	}
	list->curSize--;
}
//测试代码
    pop_front(list);
	pop_front(list);
	pop_front(list);
	pop_front(list);
	printList(list);                             //999

尾删法 

要找到表尾的上一个节点

//要删除的链表
void pop_back(LPLIST list) 
{
	if (list == NULL || list->curSize == 0)
	{
		printf("链表为空,无法删除!\n");
		return;
	}
    //从第1个节点开始找 做移动
	LPNODE preNode = list->frontNode;    //头节点
	LPNODE backNode = list->frontNode;   //头节点的下一个
	while (backNode->next != NULL) 
	{
		preNode = backNode;              //并排往下走
		backNode = preNode->next;
	}
	free(backNode);
	if (list->curSize == 1)              //只有一个节点的情况
	{
		backNode = NULL;                 //释放后置空
		list->frontNode = NULL;          //表头也要置为空
		list->backNode = NULL;           //表尾置为空
		list->curSize--;
	}
	else 
	{
		backNode = NULL;
		preNode->next = NULL;
		list->backNode = preNode;    
		list->curSize--;
	}
}
//测试代码
    pop_back(list);
	printList(list);

指定位置删除 

void pop_appoin(LPLIST list,int posData) 
{
	if (list == NULL || list->curSize == 0)
	{
		printf("链表为空,无法删除!\n");
		return;
	}
	if (list->frontNode->data == posData) //头节点的数据==指定数据 
	{
		pop_front(list);                  //头删法
		return;
	}
	if (list->backNode->data == posData) //尾节点的数据==指定数据
	{
		pop_back(list);                  //尾删法
		return;
	}
    //中间的某个情况
	LPNODE preNode = list->frontNode;    //原来的头部
	LPNODE curNode = list->frontNode->next;
	while (curNode != NULL && curNode->data != posData) 
	{
		preNode = curNode;               //并排往下走
		curNode = preNode->next;
	}
	if (curNode == NULL) 
	{
		printf("未找到指定位置,无法删除!\n");
	}
	else 
	{
		preNode->next = curNode->next;   //先连后断
		free(curNode);
		curNode = NULL;
		list->curSize--;
	}
}
//测试代码
    pop_appoin(list, 2);
	pop_appoin(list, 999);
	pop_appoin(list, 888);               //2 1 888 666 999
	printList(list);                     //1 666

查找链表

//要查找的链表 要查找的数据
LPNODE searchlist(LPLIST list, int posData)
{
	if (list == NULL)                              //list为空 返回NULL无法做删除
		return NULL;
	LPNODE pmove = list->frontNode;                //定义一个移动的节点
	while (pmove != NULL && pmove->data != posData) 
	{
		pmove = pmove->next;                       //数据!=指定数据一直往下走
	}
	return pmove;                                  //退出循环直接返回
}

删除所有指定相同的元素

void pop_all(LPLIST list, int posData) 
{
	while (searchlist(list, posData) != NULL)   //!=NULL说明里面有指定数据
	{
		pop_appoin(list, posData);              //持续做删除
	}
}
//测试代码   
	LPLIST test = createList();
	push_back(test, 1);
	push_back(test, 1);
	push_back(test, 1);
	push_back(test, 2);
	pop_all(test, 1);
	printList(test);                            //2

总结

到此这篇关于C语言实现无头单链表详解的文章就介绍到这了,更多相关C语言无头单链表内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C语言实现无头单链表详解

本文链接: https://www.lsjlt.com/news/139133.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言实现无头单链表详解
    目录链表的结构体描述(节点)再定义一个结构体(链表) 断言处理 & 判空处理创建链表创建节点头插法打印链表尾插法 指定位置插入 头删法尾删法&n...
    99+
    2022-11-13
  • C语言实现无头单向链表的示例代码
    目录一、易错的接口实现 1.1 新节点开辟函数 1.2 尾插 1.3 尾删 二、常见简单接口 2.1 打印链表 2.2 节点计数器 2.3 判断是否为空链表 2.4 通过值查找节点 ...
    99+
    2022-11-12
  • C语言链表与单链表详解
    链表是什么及链表的优势 链表是一种介于数组的另外一种数据结构: 我们知道数组可以存放很多的元素,这些元素都是呈线性排列,也就是一个挨着一个连续存放 但是当元素足够多时,还能继续正常的...
    99+
    2022-11-13
  • 详解C语言之单链表
    目录一、思路步骤1. 定义结构体2.初始化3.求当前数据元素的个数4.插入5.删除6.释放内存空间二、代码总结 一、思路步骤 1. 定义结构体 a.数据域:用来存放数据 b.指针域...
    99+
    2022-11-12
  • C语言详解无头单向非循环链表各种操作方法
    目录链表引入链表介绍创建链表打印链表创建结点单链表尾插单链表头插单链表尾删单链表头删在pos位置之前插入数据在pos位置之后插入数据删除pos位置结点删除pos位置之后的结点销毁链表...
    99+
    2022-11-13
  • C++编程语言实现单链表详情
    目录一、单链表简单介绍二、下面我们先实现单链表的初始化。 三、实现单链表的插入与删除数据一、单链表简单介绍 首先,我们再回顾一下线性表的两种存储方式——顺序存储与链式存储 上图左边...
    99+
    2022-11-12
  • C语言 超详细介绍与实现线性表中的无头单向非循环链表
    目录一、本章重点二、链表介绍三、无头单向非循环链表常用接口实现3.1动态申请一个节点3.2单链表打印3.3单链表尾插3.4单链表的头插3.5单链表的尾删3.6单链表头删3.7单链表查...
    99+
    2022-11-13
  • C语言如何实现头插法建立单链表
    目录怎么将结点一个个插入在某个结点前面呢?然后再在头结点的后面插入新的结点首先要明确一点,利用头插法建立出来的单链表的输出都是逆序的(就是和你的输入顺序反着来的)然后就是要明确生成的...
    99+
    2022-11-13
  • C语言中单链表(不带头结点)基本操作的实现详解
    目录一、单链表的概念二、单链表的基本操作1.创建单个结点2.创建具有n个结点的链表3.打印单链表4.尾插5.尾删6.头插7.头删8.查找某个结点9.在某个结点后面插入10.在某个结点...
    99+
    2022-11-16
    C语言单链表操作 C语言单链表
  • C语言详解如何实现带头双向循环链表
    目录创建链表存储结构创建结点链表的初始化双向链表的打印双向链表尾插双向链表尾删双向链表头插双向链表头删双向链表查找双向链表pos前插入结点双向链表删除pos位置的结点双向链表的销毁顺...
    99+
    2022-11-13
  • C语言实现单链表的基本功能详解
    1.首先简单了解一下链表的概念: 要注意的是链表是一个结构体实现的一种线性表,它只能从前往后,不可以从后往前(因为next只保存下一个节点的地址).在实现单链表的操作时,需要用指针...
    99+
    2022-11-12
  • C语言实现带头双向循环链表
    目录前言1. 创建结构体2.malloc新节点3.创建哨兵位节点4.尾插5.打印6.尾删7.头插8.在指定位置pos的前面进行插入9. 删除指定位置pos节点10.销毁链表前言 在...
    99+
    2022-11-13
  • C语言实现带头双向环形链表
    双向循环链表 上一次我们讲了单向无头非循环链表的实现,单向无头非循环链表的特点是:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构。而带头双向循环链表则恰恰与无...
    99+
    2022-11-12
  • C语言中单链表如何实现
    这篇文章主要介绍“C语言中单链表如何实现”,在日常操作中,相信很多人在C语言中单链表如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C语言中单链表如何实现”的疑惑有所帮助!接下来,请跟着小编一起来学习吧...
    99+
    2023-07-04
  • C语言学习之链表的实现详解
    目录一、链表的概念二、链表的结构三、顺序表和链表的区别和联系四、链表的实现一、链表的概念 链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次...
    99+
    2022-11-13
    C语言 链表实现 C语言 链表
  • C语言超详细讲解双向带头循环链表
    目录一、双向带头循环链表的结构二、双向带头循环链表的函数接口1. 申请结点2. 初识化3. 打印4. 尾插尾删5. 头插头删6. 查找7. 中间插入和删除8. 判空及求链表长度9. ...
    99+
    2023-02-14
    C语言双向带头循环链表 C语言带头循环链表 C语言循环链表
  • C语言如何实现单链表操作
    本篇内容介绍了“C语言如何实现单链表操作”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1 链表的概念及结构概念:链表是一种物理存储结构上非连...
    99+
    2023-06-29
  • C++详解如何实现单链表
    目录单链表单链表的基本操作1.初始化2.取值3.查找4.插入5.删除示例代码开发环境运行结果单链表 链表内存空间不一定连续,其扩展性较好。多余的不多说了。该文主要记录单链表的实现,该...
    99+
    2022-11-13
  • C语言单链表实例分析
    今天小编给大家分享一下C语言单链表实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1、移除链表元素链接直达:移除链表元...
    99+
    2023-06-30
  • C语言线性表的链式表示及实现详解
    目录前言代码实现1. 单链表的结点构造2. 构造一个空的头结点3. 对线性表进行赋值4.对线性表进行销毁5.对线性表进行重置6.判断线性表是否为空7.获取线性表的长度8.获取线性表某...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作