无头单向不循环链表和带头双向循环链表的创建

news2024/11/15 5:20:14

 Lei宝啊:个人主页

愿所有美好不期而遇



 

前言:

 

接下来我们将会了解最基础的链表--->单链表

以及最方便也是最爽的链表--->带头双向循环链表。

 

 若有看不懂之处,可画图或者借鉴这里:反转单链表,对于数据结构而言,无非就是增删查改,当我们能够熟练应用以及画图后,其OJ题和以下代码都是小卡拉米。

 

无头单向不循环链表

单链表图:

 

头文件:

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

typedef int DataType;

typedef struct STLNode
{
	DataType data;
	struct STLNode* next;
}STLNode;

void STL_Print(STLNode* phead);
void STL_PushBack(STLNode** pphead, DataType x);
void STL_PushFront(STLNode** pphead, DataType x);
void STL_PopBack(STLNode** pphead);
void STL_PopFront(STLNode** pphead);
STLNode* STL_Find(STLNode* phead, DataType x);
void STL_InsertAfter(STLNode* pos, DataType x);
void STL_EraseAfter(STLNode* pos);
void STL_Destroy(STLNode** pphead);

Test文件:

#include "STLNode.h"

void Test1(STLNode* phead);

int main()
{
	
	STLNode* plist = NULL;

	Test1(plist);
	return 0;
}

void Test1(STLNode* phead)
{
	
	STL_PushBack(&phead, 1);
	STL_PushBack(&phead, 2);
	STL_PushBack(&phead, 3);
	STL_Print(phead);

	STL_PushFront(&phead, 11);
	STL_PushFront(&phead, 22);
	STL_PushFront(&phead, 33);
	STL_Print(phead);

	STLNode* ret = STL_Find(phead, 1);
	STL_InsertAfter(ret, 666);
	STL_Print(phead);

	STL_EraseAfter(ret);
	STL_Print(phead);

	STL_Destroy(&phead);
	STL_Print(phead);
	//STL_PopBack(&phead);
	//STL_PopBack(&phead);
	//STL_Print(phead);

	//STL_PopFront(&phead);
	//STL_PopFront(&phead);
	//STL_Print(phead);


}

函数源文件:

对于以下函数中部分有对phead和pphead的检查,部分没有,原因是这样的:

对于是否需要对其进行断言,我们是要看他为NULL时合不合理,合理就不断言,不合理就断言,例如STL_Printf函数中,当phead为NULL时,说明该链表是空的,直接打印NULL就可以,这是很合理的。而对于STL_PushBack函数来说,phead为NULL同样合理,因为phead为NULL我们尾插其实也就相当于头插,很合理,但是对于pphead来说,他作为plist的地址,就算plist为NULL,pphead是不应该为NULL的,所以他为NULL就非常不合理,我们要对其进行断言检查。

#include "STLNode.h"

void STL_Print(STLNode* phead)
{

	while (phead)
	{
		printf("%d->", phead->data);
		phead = phead->next;
	}
	printf("NULL\n");

}

STLNode* Malloc(DataType x)
{
	STLNode* temp = (STLNode*)malloc(sizeof(STLNode));
	if (temp == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	temp->data = x;
	temp->next = NULL;

	return temp;
}

void STL_PushBack(STLNode** pphead, DataType x)
{
	assert(pphead);

	STLNode* temp = Malloc(x);

	if (*pphead == NULL)
	{
		*pphead = temp;
	}
	else
	{
		STLNode* cur = *pphead;
		while (cur->next != NULL)
		{
			cur = cur->next;
		}
		cur->next = temp;
	}
}

void STL_PushFront(STLNode** pphead, DataType x)
{
	assert(pphead);

	STLNode* temp = Malloc(x);
	temp->next = *pphead;
	*pphead = temp;

}

void STL_PopBack(STLNode** pphead)
{
	assert(pphead);
	assert(*pphead);

	STLNode* cur = *pphead;
	STLNode* temp = *pphead;
	
	if (cur->next == NULL)
	{
		free(cur);
		*pphead = NULL;
	}
	else
	{
		while (cur->next)
		{
			temp = cur;
			cur = cur->next;
		}
		free(cur);
		temp->next = NULL;
	}
	
}

void STL_PopFront(STLNode** pphead)
{
	assert(pphead);
	assert(*pphead);

	STLNode* cur = *pphead;
	*pphead = (*pphead)->next;
	free(cur);

}

STLNode* STL_Find(STLNode* phead, DataType x)
{
	if (phead == NULL)
	{
		printf("NULL\n");
		return;
	}

	while (phead != NULL)
	{
		if (phead->data == x)
		{
			return phead;
		}
		phead = phead->next;
	}

	printf("Can not find\n");
	return;
}

void STL_InsertAfter(STLNode* pos, DataType x)
{
	assert(pos);

	STLNode* temp = Malloc(x);
	temp->next = pos->next;
	pos->next = temp;

}

void STL_EraseAfter(STLNode* pos)
{
	assert(pos);
	assert(pos->next);

	STLNode* cur = pos->next;
	pos->next = pos->next->next;

	free(cur);
}

void STL_Destroy(STLNode** pphead)
{
	assert(pphead);
	if (*pphead == NULL)
	{
		return;
	}

	STLNode* temp = *pphead;
	STLNode* cur = *pphead;
	while (temp)
	{
		cur = temp->next;
		free(temp);
		temp = cur;
	}
	*pphead = NULL;
}



 

带头双向循环链表

图:

 

头文件:

这个链表最爽的地方在于,他可以很轻松地找到尾,不管是尾插还是头插都非常爽,非常方便,如果我们想在半小时内写完这个链表,那么就可以对尾插和头插复用LTInsert函数,对于尾删和头删复用LTErase函数,也就是说,这两个函数是核心函数,有了他们,迅速写完该链表成为现实。

尾插的复用:LTInsert(phead,x);

头插的复用:LTInsert(phead->next,x);

尾删的复用:LTErase(phead->prev);

头删的复用:LTErase(phead->next);

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

typedef int DataType;

typedef struct LTNode
{
	DataType data;
	struct LTNode* prev;
	struct LTNode* next;
}LTNode;

LTNode* Init();
LTNode* Malloc(DataType x);
LTNode* LTFind(LTNode* phead, DataType x);
void LTPrintf(LTNode* phead);
void LTPushBack(LTNode* phead, DataType x);
void LTPopBack(LTNode* phead);
void LTPushFront(LTNode* phead, DataType x);
void LTPopFront(LTNode* phead);
void LTInsert(LTNode* pos, DataType x);   //在pos位置前插入节点
void LTErase(LTNode* pos);                //删除pos位置节点
void LTDestroy(LTNode* phead);

 Test文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include "LTNode.h"

void Test1();

int main()
{
	Test1();
	return 0;
}

void Test1()
{
	LTNode* plist = NULL;
	plist = Init();

	LTPushBack(plist, 1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);
	LTPushBack(plist, 4);
	LTPushBack(plist, 5);
	LTPushBack(plist, 6);
	LTPrintf(plist);

	LTPopBack(plist);
	LTPopBack(plist);
	LTPopBack(plist);
	LTPrintf(plist);

	LTPushFront(plist, 10);
	LTPushFront(plist, 20);
	LTPushFront(plist, 30);
	LTPrintf(plist);

	LTPopFront(plist);
	LTPrintf(plist);

	LTNode *pos = LTFind(plist, 10);
	LTInsert(pos, 66);
	LTPrintf(plist);
	LTErase(pos);
	LTPrintf(plist);

	LTDestroy(plist);
	plist = NULL;

}

函数源文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include "LTNode.h"

LTNode* Malloc(DataType x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = x;
	return newnode;
}

LTNode* Init()
{
	LTNode* newnode = Malloc(0);

	newnode->next = newnode;
	newnode->prev = newnode;

	return newnode;
}

void LTPrintf(LTNode* phead)
{
	assert(phead);

	printf("phead<=>");
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d<=>", cur->data);
		cur = cur->next;
	}
	putchar('\n');
}

void LTPushBack(LTNode* phead, DataType x)
{
	assert(phead);

	LTNode *newnode = Malloc(x);
	LTNode* tail = phead->prev;

	tail->next = newnode;
	newnode->prev = tail;

	newnode->next = phead;
	phead->prev = newnode;

}

void LTPopBack(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);

	LTNode* tail = phead->prev;
	LTNode* newtail = tail->prev;

	newtail->next = phead;
	phead->prev = newtail;
	free(tail);
}

void LTPushFront(LTNode* phead, DataType x)
{
	assert(phead);

	LTNode* newnode = Malloc(x);
	LTNode* old_next = phead->next;

	phead->next = newnode;
	newnode->prev = phead;

	newnode->next = old_next;
	old_next->prev = newnode;

}

void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);

	LTNode* del = phead->next;

	phead->next = del->next;
	del->next->prev = phead;

	free(del);
}

LTNode* LTFind(LTNode* phead, DataType x)
{
	assert(phead);
	
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}

	printf("nothing!\n");
	return NULL;
}

void LTInsert(LTNode* pos, DataType x)
{
	assert(pos);

	LTNode* newnode = Malloc(x);
	LTNode* posprev = pos->prev;

	posprev->next = newnode;
	newnode->prev = posprev;

	newnode->next = pos;
	pos->prev = newnode;
}

void LTErase(LTNode* pos)
{
	assert(pos);

	LTNode* posprev = pos->prev;
	LTNode* posnext = pos->next;

	posprev->next = posnext;
	posnext->prev = posprev;
	free(pos);
}

void LTDestroy(LTNode* phead)
{
	assert(phead);

	LTNode* cur = phead->next;
	while (cur != phead)
	{
		LTNode* next = cur->next;
		free(cur);
		cur = next;
	}

	free(cur);
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/832961.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python入门【​编辑、组合、设计模式_工厂模式实现 、设计模式_单例模式实现、工厂和单例模式结合、异常是什么?异常的解决思路 】(十七)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小王&#xff0c;CSDN博客博主,Python小白 &#x1f4d5;系列专栏&#xff1a;python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 &#x1f4e7;如果文章知识点有错误…

解决Vue3 使用Element-Plus导航刷新active高亮消失

解决Vue3 使用Element-Plus导航刷新后active高亮消失的问题 启用路由模式会在激活导航时以 index 作为 path 进行路由跳转 使用 default-active 来设置加载时的激活项。 接下来打印一下选中项index和index路径&#xff0c; 刷新也是没有任何问题的&#xff0c;active不会消失…

NB-IOT 和蜂窝通信(2/3/4/5G)的区别和特点是什么?

NB-IOT 和蜂窝通信(2/3/4/5G)的区别和特点是什么? 参考链接:https://www.sohu.com/a/221664826_472880 NB IOT是窄带物联网技术,主要解决的是低速率数据传输,可使用GSM900或DCS1800频段,在频段使用上比较灵活,可以和GSM,UMTS或LTE共存,具备优异的MCL(最小耦合损耗…

ZKML——EZKL团队分享

1. 引言 “ZKP之于数字签名” 类似于 “以太坊之于比特币”&#xff1a; 所谓数字签名&#xff0c;是指&#xff1a;“我知道某秘密secrets&#xff0c;使得 F(secrets, public inputs)pubic outputs”&#xff0c;其中F为fixed function&#xff08;固定函数&#xff09;。这…

【雕爷学编程】 MicroPython动手做(34)——通用传感器的综合运用

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

71. 简化路径

题目链接&#xff1a;力扣 解题思路&#xff1a; 以 "/" 对路径字符串进行分割&#xff0c;得到分割后的数组split&#xff0c;那么数组中每个元素就是一级路径的名称对split进行遍历&#xff1a;使用一个队列deque保存最终的每一个目录 如果当前字符串是 "..&…

发明专利申请:不能包含文本框或自选图形 || 不能包含域对象(校验错误)

提交出错 解决方案&#xff1a;如果xml文件传上去没有反应&#xff0c;一定要优先把word转成pdf&#xff0c;不要去文本框中输入&#xff1a;里面的公式编辑器很老旧&#xff08;很多公式编辑不了&#xff09; 上传以后&#xff0c;总体预览没有问题就ok&#xff0c;前序穿文件…

【GitOps系列】如何实施自动化渐进式交付?

文章目录 前言自动渐进式交付概述自动渐进式交付准备创建生产环境创建 AnalysisTemplate访问生产环境安装Prometheus配置 Ingress-Nginx 和 ServiceMonitor验证 Ingress-Nginx 指标 自动渐进式交付实战自动渐进式交付成功自动渐进式交付失败 结语 前言 在实施金丝雀发布的过程中…

Golang之路---03 面向对象——反射

反射 反射的存在意义 在开发中&#xff0c;你或许会碰到在有些情况下&#xff0c;你需要获取一个对象的类型&#xff0c;属性及方法&#xff0c;而这个过程其实就是反射。 golang中变量包括&#xff08;type, value&#xff09;两部分 静态类型 所谓的静态类型&#xff08;…

【智慧校园】智慧班牌云平台源码,使用springboot vue框架

【智慧校园】智慧班牌云平台源码&#xff0c;使用springboot vue框架 前后端分离架构 1、使用springboot vue框架 2、数据库MySQL5.7 3、移动端小程序使用小程序原生语言开发 4、电子班牌固件安卓7.1&#xff1b;使用Java Android原生 5、java&#xff0c;elmentui &…

四、Unity中颜色空间

Unity中的设置 通过点击菜单Edit->Project Settings->Player页签->Other Settings下的Rendering部分进行修改&#xff0c;参数Color Space可以选择Gamma或Linear。 当选择Gamma Space时&#xff0c;Unity不会做任何处理。当选择Linear Space时&#xff0c;引擎的渲染…

电测知识分享——三千字解读时钟电路最重要部件,建议收藏!

晶振作为时钟电路中最重要的部件&#xff0c;在电路中起着产生震荡频率的作用&#xff0c;可以产生高度稳定的信号&#xff0c;并稳定工作环境&#xff0c;为系统提供基本的时钟信号&#xff0c;在工业、科技、车载、数码、电子等多个领域几乎都有应用场景。 今天&#xff0c;…

MySQL binLog问题

看到数据库目录下有很多OFF.*文件的时候很诧异&#xff0c;这玩意是啥&#xff0c;binlog不应该都是*bin-log.*​的文件吗&#xff1f;* [roottest ~]# cd /data/mysql_data [roottest mysql_data]# ls ansible hap_attach_yl hap_func_yl hap_msg_yl h…

区块链媒体发稿:区块链媒体宣发常见问题解析

据统计&#xff0c;由于区块链应用和虚拟货币的兴起&#xff0c;越来越多媒体对区块链领域开展报导&#xff0c;特别是世界各国媒体宣发全是热火朝天。但是&#xff0c;随着推卸责任媒体宣发的五花八门&#xff0c;让很多人因而上当受骗&#xff0c;乃至伤害一大笔资产。身为投…

【TiDB理论知识08】HATP概述

1 HTAP技术 OLTP 在线事务 支付 转账 高并发 每次操作的数据量少 &#xff0c;行存 OLAP 报表分析 每次操作大量数据 列存储 2 传统解决方案 数据抽取到数仓或者数据湖 ETL有延迟 &#xff0c;一般会有T1 T2 数据多副本 3 HTAP的要求 4 TIDB的HTAP架构 TiFlash特点&…

IO进程线程day6(2023.8.3)

一、Xmind整理&#xff1a; 进程与线程关系&#xff1a; 二、课上练习&#xff1a; 练习1&#xff1a;pthread_create 功能&#xff1a;创建一个线程 原型&#xff1a; #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, vo…

【新版系统架构补充】-七层模型

网络功能和分类 计算网络的功能 &#xff1a;数据通信、资源共享、管理集中化、实现分布式处理、负载均衡 网络性能指标&#xff1a;速率、带宽&#xff08;频带宽度或传送线路速率&#xff09;、吞吐量、时延、往返时间、利用率 网络非性能指标&#xff1a;费用、质量、标准化…

三、基本流程控制结构

3.1结构化程序设计 基本控制结构&#xff1a; 顺序结构选择结构循环结构 C语句&#xff1a; 说明语句控制语句函数调用语句表达式语句空语句复合语句 3.2选择结构语句 if语句&#xff1a; &#xff08;1&#xff09;单选条件语句 if(表达式) 语句 if(x>y) cout<&l…

Tomcat的介绍和安装配置、eclipse中动态web项目的创建和运行、使用IDEA创建web项目并运行

一、Tomcat的介绍和安装配置 安装tomcat&#xff1a; 环境变量的配置&#xff1a; 配置之后重启cmd&#xff0c;执行startup命令&#xff0c;启动tomcat 在localhost:8080&#xff0c;能进入tomcat主界面&#xff0c;说明配置成功 二、eclipse中动态web项目的创建和运行 tomca…

基于回溯算法实现八皇后问题

八皇后问题是一个经典的计算机科学问题&#xff0c;它的目标是将8个皇后放置在一个大小为88的棋盘上&#xff0c;使得每个皇后都不会攻击到其他的皇后。皇后可以攻击同一行、同一列和同一对角线上的棋子。 一、八皇后问题介绍 八皇后问题最早由国际西洋棋大师马克斯贝瑟尔在18…