单链表操作 C实现

news2024/12/25 17:13:30

struct LNode { //定义一个节点

        int data; //数据域

        struct LNode *next; //指针域

};

0.初始化

typedef sturct LNode{                      //定义单链表结点类型      
    int date ;                //每个结点存放一个数据元素
    struct LNode *next;            //指针指向下一个结点
}LNodes, *LinkList;
typedef  LNode{                      //定义单链表结点类型      
    int date ;                //每个结点存放一个数据元素
    struct LNode *next;            //指针指向下一个结点
};

//typedef struct LNode LNodes;
//typedef struct LNOde *LinkList;
//上面俩个是等价的

1)不带头结点的单链表
bool InitList(LinkList &L)      //初始化空链表
{
     L = NULL;                 //空表没有任何结点
     return true;           
}

void test()
{
     LinkList L ;         //声明一个指向单链表的指针
     //初始化一个空表
     InitList (L);
}

判断是否为空
bool Empty(LinkList L){
    if(L == NULL)
       return true;
    else 
       return false;
}
//或:
bool Empty(LinkList L){
     return (L == NULL);
}

2)带头节的单链表
//初始化一个单链表(带头结点)
bool InitList (LinkList &L){
     L = (LNode * ) malloc (sizeof(LNode));        //分配一个头结点
     if (L == NULL)                                //内存不足分配失败
        return false; 
     L->next  = NULL;
     return true;
}

判断是否为空
bool Empty(LinkList L){
     if(L->next == NULL)
         return true;
     else 
         return false;
}


1.尾插法建立链表

struct LNode *CreateLinkList1(void){  //尾插法创建链表
	struct LNode *head=(struct LNode *)malloc(LEN); //创建一个头节点
	head->next=NULL; //开始时头节点指针指向NULL
	struct LNode *h=head,*s;
	struct LNode info;//接收从键盘输入每个节点的数据
	scanf("%d",&info.data);
	while(info.data!=0){  //创建链表,直到输入数据为0结束
		s=(struct LNode *)malloc(LEN);
		s->data=info.data;  //节点s接收输入数据
		h->next=s; //尾插如链表尾部
		h=h->next;  //保持h位于链表末尾,方便接收下一个节点数据
		scanf("%d",&info.data);
	}
	h->next=NULL;  //链表末尾指向NULL
	return head;
}

typedef struct LNode {

       int data; //数据域

       struct LNode *next; //指针域

  }LNodes,*LinkList;


LNodes *insertFront(LNodes *head, LNodes *newNode) 
{
    newNode->next = head->next;
    head->next = newNode;
    return head;
}

2.头插法建立链表

struct LNode *CreateLinkList2(void){  //头插法创建链表
	struct LNode *head=(struct LNode *)malloc(LEN);
	head->next=NULL;
	struct LNode *h=head,*s;
	struct LNode info;
	scanf("%d",&info.data);
	while(info.data!=0){  //创建链表,直到输入数据为0结束
		s=(struct LNode *)malloc(LEN);
		s->data=info.data;//节点s接收输入数据
		s->next=h->next;  //头插插入头节点尾部,插入节点要始终跟着头节点后面
		h->next=s; 
		scanf("%d",&info.data);
	}
	return head;
}

typedef struct LNode {

       int data; //数据域

       struct LNode *next; //指针域

  }LNodes,*LinkList;


LNodes *insertBack(LNodes *head, LNodes *tail, LNodes *newNode) 
{
    newNode->next = NULL;
    tail->next = newNode;
    tail = newNode;
    return head;
}

3.链表结点删除操作

struct LNode *Delete(struct LNode *head,int x){ //删除链表中值为x的节点
	struct LNode *p=head->next,*pre=head,*q;
	while(p!=NULL){
		if(p->data==x){
			q=p;
			pre->next=p->next;
			p=p->next;
			free(q);
		}
		else{
			pre=p;
			p=p->next;
		}
	}
	return head;
}

4.在有序链表中插入一个结点

struct LNode *Insert(struct LNode *head,int x){  //创建一个递增链表,将x插入链表,并保持有序
	struct LNode *p=head->next,*pre=head,*q;
	while(p!=NULL){
		if(x<p->data){
			q=(struct LNode *)malloc(LEN);  //为插入值分配一个节点空间
			q->data=x;
			pre->next=q;
			q->next=p;
			break;
		}
		else{
			pre=p;
			p=p->next;
		}
	}
	return head;
}

5.遍历

void print(struct LNode *head){ //遍历链表并输出各个节点的数据
	struct LNode *p=head->next;
	while(p!=NULL){
		printf("%d->",p->data);
		p=p->next;
	}
	printf("NULL\n");
}

运行程序结果:

尾插法:1 2 3 4 6 7 8 9 0
1->2->3->4->6->7->8->9->NULL
头插法:1 2 3 4 6 7 8 9 0
9->8->7->6->4->3->2->1->NULL
删除节点8:1->2->3->4->6->7->9->NULL
插入节点5:1->2->3->4->5->6->7->9->NULL
Press any key to continue...

完整的代码如下:

#include <stdio.h>
#include <stdlib.h>
#define LEN sizeof(struct LNode)  //LEN表示一个节点大小
struct LNode{  //定义一个节点
	int data; //数据域
	struct LNode *next; //指针域
};
struct LNode *CreateLinkList1(void){  //尾插法创建链表
	struct LNode *head=(struct LNode *)malloc(LEN); //创建一个头节点
	head->next=NULL; //开始时头节点指针指向NULL
	struct LNode *h=head,*s;
	struct LNode info;//接收从键盘输入每个节点的数据
	scanf("%d",&info.data);
	while(info.data!=0){  //创建链表,直到输入数据为0结束
		s=(struct LNode *)malloc(LEN);
		s->data=info.data;  //节点s接收输入数据
		h->next=s; //尾插如链表尾部
		h=h->next;  //保持h位于链表末尾,方便接收下一个节点数据
		scanf("%d",&info.data);
	}
	h->next=NULL;  //链表末尾指向NULL
	return head;
}
struct LNode *CreateLinkList2(void){  //头插法创建链表
	struct LNode *head=(struct LNode *)malloc(LEN);
	head->next=NULL;
	struct LNode *h=head,*s;
	struct LNode info;
	scanf("%d",&info.data);
	while(info.data!=0){  //创建链表,直到输入数据为0结束
		s=(struct LNode *)malloc(LEN);
		s->data=info.data;//节点s接收输入数据
		s->next=h->next;  //头插插入头节点尾部,插入节点要始终跟着头节点后面
		h->next=s; 
		scanf("%d",&info.data);
	}
	return head;
}
struct LNode *Delete(struct LNode *head,int x){ //删除链表中值为x的节点
	struct LNode *p=head->next,*pre=head,*q;
	while(p!=NULL){
		if(p->data==x){
			q=p;
			pre->next=p->next;
			p=p->next;
			free(q);
		}
		else{
			pre=p;
			p=p->next;
		}
	}
	return head;
}
struct LNode *Insert(struct LNode *head,int x){  //创建一个递增链表,将x插入链表,并保持有序
	struct LNode *p=head->next,*pre=head,*q;
	while(p!=NULL){
		if(x<p->data){
			q=(struct LNode *)malloc(LEN);  //为插入值分配一个节点空间
			q->data=x;
			pre->next=q;
			q->next=p;
			break;
		}
		else{
			pre=p;
			p=p->next;
		}
	}
	return head;
}
void print(struct LNode *head){ //遍历链表并输出各个节点的数据
	struct LNode *p=head->next;
	while(p!=NULL){
		printf("%d->",p->data);
		p=p->next;
	}
	printf("NULL\n");
}
int main(void){
	struct LNode *p1,*p2,*q,*y;
	printf("尾插法:");
	p1=CreateLinkList1(); //p1接收尾插法传回的头节点
	print(p1);
	printf("头插法:");
	p2=CreateLinkList2(); //p2接收头插法传回的头节点
	print(p2);
	printf("删除节点8:");
	q=Delete(p1,8);
	print(p1);
	printf("插入节点5:");
	y=Insert(p1,5);
	print(y);
}

头插法和尾插法详解

头插法
核心代码:
head->next = NULL;
s->next = head->next;
head->next = s;

单个结点


原始状态


第一个元素插入的过程(注意:1和2的顺序不能颠倒,不然会导致链表缺失)


第一个元素插入后


第二个元素插入的过程(其余元素插入的过程也类似)


第二个元素插入后

尾插法
核心代码:
tail = head;
s->next = NULL;
tail->next = s;
tail = s;

原始状态


第一个元素插入的过程(注意:2和3的顺序不能颠倒,不然会导致链表的生成出错)


第一个元素插入后


第二个元素插入的过程(其余元素插入的过程也类似)


第二个元素插入后


头插法和尾插法的对比
头插法建立链表的算法简短易懂,但是生成链表的结点顺序与原来输入的顺序相反,而用尾插法建立链表可使输入和生成的结点顺序相同

为什么会这样呢?
根据上面的头插法和尾插法的算法,我们很容易知道,当用头插法依次插入值分别为1,2,3,4,5的结点(也叫做元素)后,单链表会如下图所示:


但是用尾插法同样插入值分别为1,2,3,4,5的结点后,单链表却会如下图所示:

而在这两个链表中,输出链表中各个元素的值只能从已知的头结点head开始遍历,所以分别用头插法和尾插法创建链表后,依次输出的元素的值刚好是相反的

验证小例子:

#include <stdio.h>
#include <malloc.h>

typedef struct node
{
	struct node* next;
	int data;
 }LinkList; 
 //定义LinkList为struct node类型,即struct node可直接用LinkList来表示,方便定义
 
//头插法创建单链表 
int main (void)
{
	int i, len = 5;
//len表示链表的长度	
	LinkList* head, * s;
//head为LinkList*类型的指针变量,表示头指针
	head = (LinkList*)malloc (sizeof (LinkList));
//malloc (sizeof (LinkList))意思是让系统分配内存大小为sizeof (LinkList)的空间
	head->next = NULL;
//令头指针的所指向结点的指针域为空
	for (i = 0; i < len; i++)
	{
		s = (LinkList*)malloc (sizeof (LinkList));
		printf ("请输入该元素的值:");
		scanf ("%d", &s->data);
		s->next = head->next;
		head->next = s;
	}
//以下代码是为了将单链表中各个元素的值依次打印出来	
	LinkList* q;
	q = (LinkList*)malloc (sizeof (LinkList));
	q = head->next;
	while (q != NULL)
	{
		printf ("%d", q->data);
		q = q->next;
	}
	return 0;
}


结果:
请输入该元素的值:1
请输入该元素的值:2
请输入该元素的值:3
请输入该元素的值:4
请输入该元素的值:5
54321

#include <stdio.h>
#include <malloc.h>


typedef struct node
{
	struct node* next;
	int data;
 }LinkList; 
 
//尾插法创建单链表
int main (void)
{
	int i, len = 5;
	LinkList* head,* s,* tail;
//tail表示尾指针	
	head = (LinkList*)malloc (sizeof (LinkList));
	tail = head;
	for (i = 0; i < len; i++)
	{
		s = (LinkList*)malloc (sizeof (LinkList));
		printf ("请输入该元素的值:");
		scanf ("%d", &s->data); 
		s->next = NULL;
		tail->next = s;
		tail = s;
    }
 //以下代码是将单链表中各个元素的值依次打印出来   
    LinkList* q;
    q = head->next;
    while (q != NULL)
    {
    	printf ("%d", q->data);
    	q = q->next;
	}
    return 0;
 } 



结果:
请输入该元素的值:1
请输入该元素的值:2
请输入该元素的值:3
请输入该元素的值:4
请输入该元素的值:5
12345
————————————————
 

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

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

相关文章

leetCode 62.不同路径 动态规划 + 空间复杂度优化

62. 不同路径 - 力扣&#xff08;LeetCode&#xff09; 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xf…

运行软件mfc100u.dll缺失是怎么办?mfc100u.dll丢失解决方法分享

Mfc100u.dll 丢失的问题可能困扰着许多使用计算机的用户。Mfc100u.dll 是一个重要的动态链接库文件&#xff0c;它包含了许多功能模块&#xff0c;如字符串处理、数学计算、文件操作等。当 Mfc100u.dll 文件丢失或损坏时&#xff0c;可能会导致许多应用程序无法正常运行&#x…

【深度学习实验】卷积神经网络(六):卷积神经网络模型(VGG)训练、评价

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. 构建数据集&#xff08;CIFAR10Dataset&#xff09; a. read_csv_labels&#xff08;&#xff09; b. CIFAR10Dataset 2. 构建模型&#xff08;FeedForward&…

Chrome(谷歌浏览器)如何关闭搜索栏历史记录

目录 问题描述解决方法插件解决&#xff08;亲测有效&#xff09;自带设置解决步骤首先打开 地址 输入&#xff1a;chrome://flags关闭浏览器&#xff0c;重新打开Chrome 发现 已经正常 问题描述 Chrome是大家熟知的浏览器&#xff0c;但是搜索栏的历史记录如何自己一条条的删…

学校宿舍一键视频对讲

学校宿舍一键视频对讲 大学宿舍一键视频对讲是指在大学宿舍内安装一套视频对讲系统&#xff0c;通过一键操作&#xff0c;实现与宿舍内其他人进行视频通话的功能。 该系统通常包括以下组成部分&#xff1a; 1. 室内终端&#xff1a;每个宿舍内安装一个室内终端&#xff0c;室…

JavaScript求数组的交集和差集

1. 求交集(从2个数组中找到相同的元素, 组成新数组, 注意去重): 1) Setfilterincludes // 求交集: const arr1 [0, 1, 2] const arr2 [3, 2, 0] function intersectSet(arr1, arr2) {return [...new Set(arr1)].filter(item>arr2.includes(item)) } const values inter…

26593-2011 无损检测仪器 工业用X射线CT装置性能测试方法

声明 本文是学习GB-T 26593-2011 无损检测仪器 工业用X射线CT装置性能测试方法. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了工业用X 射线CT 装置(以下简称CT 装置)性能测试的术语、定义、缩略语以及空间 分辨力、密度分辨率…

BChecks 自定义poc检测 - 把BurpSuite 打造成强大的漏洞扫描器

BChecks是什么&#xff1f; BChecks可以创建和导入的自定义扫描检查。Burp Scanner在执行其内置扫描例程的同时运行这些检查&#xff0c;帮助您定位扫描并使测试工作流尽可能高效。 每个BCheck都定义为一个以.bcheck文件扩展名结尾的纯文本文件。这些文件使用自定义语言来指定…

配置OSPF路由

OSPF路由 1.OSPF路由 1.1 OSPF简介 OSPF(Open Shortest Path First&#xff0c;开放式最短路径优先&#xff09;路由协议是另一个比较常用的路由协议之一&#xff0c;它通过路由器之间通告网络接口的状态&#xff0c;使用最短路径算法建立路由表。在生成路由表时&#xff0c;…

Spring Cloud Netflix 教程和源码

本教程目标 想要系统地学习 Spring Cloud Netflix&#xff0c; 把自己的学习过程记录下来。 状态 持续更新中 微服务架构 微服务架构是一种将应用程序拆分为一组独立的、可独立部署的服务的架构模式。每个服务都运行在自己的进程中&#xff0c;可以独立地进行开发、测试和…

数据库管理-第108期 因Exadata存储节点操作系统空间异常的紧急处理(20230928)

数据库管理-第108期 因Exadata存储节点操作系统空间异常的紧急处理&#xff08;20230928&#xff09; 众所周知&#xff0c;明天放假了&#xff0c;本着对客户数据库软硬件负责任的态度&#xff0c;进行了一次深入彻底的软硬件巡检&#xff08;就是检查包括计算节点、存储节点…

vue3中状态适配

写一个函数&#xff0c;在函数中定义一个对象 用于存放键值对&#xff0c;最后返回指定状态所对应的的值&#xff0c;即对象[指定状态] 的 对象的值。 在模板中把状态传入 // vue3 setup语法糖中 const formatXXXState (xxxState)>{const stateMap {键1: 值1,键2: 值2,.…

Linux-正则三剑客

目录 一、正则简介 1.正则表达式分两类&#xff1a; 2.正则表达式的意义 二、Linux三剑客简介 1.文本处理工具&#xff0c;均支持正则表达式引擎 2.正则表达式分类 3.基本正则表达式BRE集合 4.扩展正则表达式ere集合 三、grep 1.简介 2.实践 3.贪婪匹配 四、sed …

VS+Qt+opencascade三维绘图stp/step/igs/stl格式图形读取显示

程序示例精选 VSQtopencascade三维绘图stp/step/igs/stl格式图形读取显示 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《VSQtopencascade三维绘图stp/step/igs/stl格式图形读取显示》编写…

postman安装使用教程

本文只是基于 Chrome 浏览器的扩展插件来进行的安装&#xff0c;并非单独应用程序。 首先&#xff0c;你要台电脑&#xff0c;其次&#xff0c;安装有 Chrome 浏览器&#xff0c;那你接着往下看吧。 1. 官网安装&#xff08;别看&#xff09; 打开官网&#xff0c;https://ww…

【计算机网络】P2P文件分发介绍

文章目录 P2P体系结构的自扩展性BitTorrent协议参考资料 考虑一个场景&#xff1a;从单一服务器向大量主机&#xff08;称为对等方&#xff09;分发一个大文件。 两种处理方式 客户-服务器文件分发&#xff1a;服务器需要向每个对等方发送该文件的一个副本 P2P文件分发&#xf…

使用代理后pip install 出现ssl错误

window直接设置代理 httphttp://127.0.0.1:7890;httpshttp://127.0.0.1

Java 并发编程面试题——BlockingQueue

目录 1.什么是阻塞队列 (BlockingQueue)&#xff1f;2.BlockingQueue 有哪些核心方法&#xff1f;3.BlockingQueue 有哪些常用的实现类&#xff1f;3.1.ArrayBlockingQueue3.2.DelayQueue3.3.LinkedBlockingQueue3.4.PriorityBlockingQueue3.5.SynchronousQueue 4.✨BlockingQu…

【C++】构造函数和析构函数第二部分(拷贝构造函数)--- 2023.9.28

目录 什么是拷贝构造函数&#xff1f;编译器默认的拷贝构造函数构造函数的分类及调用结束语 什么是拷贝构造函数&#xff1f; 用一句话来描述为拷贝构造即 “用一个已知的对象去初始化另一个对象” 具体怎么使用我们直接看代码&#xff0c;代码如下&#xff1a; class Maker…

什么是DOM和DOM操作

什么是DOM&#xff1f; DOM&#xff08;文档对象模型&#xff09;:HTML文档的结构化表示。允许JavaScript访问HTML元素和样式来操作它们。&#xff08;更改文本&#xff0c;HTML属性甚至CSS样式&#xff09; 树结构由HTML加载后自动生成 DOM树结构 这个是一个很简单的HTML代…