【数据结构】单向链表的增删查改以及指定pos位置的插入删除

这篇具有很好参考价值的文章主要介绍了【数据结构】单向链表的增删查改以及指定pos位置的插入删除。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

 单向链表的概念及结构

 尾插

头插

尾删

​编辑

 头删

 查找

 在pos位置前插

 在pos位置后插

 删除pos位置

 删除pos的后一个位置

总结

代码 


 单向链表的概念及结构

概念:链表是一种 物理存储结构上非连续 、非顺序的存储结构,数据元素的 逻辑顺序 是通过链表中的指针链接 次序实现的。

 单向链表的结构:【数据结构】单向链表的增删查改以及指定pos位置的插入删除,数据结构,数据结构,链表

注意:

  1. 从上图可看出,链式结构在逻辑上是连续的,但是在物理上不一定连续。
  2. 现实中的结点一般都是从堆上申请出来的。
  3. 从堆上申请的空间,是按照一定的策略来分配的,两次申请的空间可能连续,也可能不连续。 
  •  无头单向非循环链表:结构简单, 一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。

 尾插

尾插分为两种情况:

  1. 一开始没有链表:当开始没有链表,直接将newnode赋给*pphead,通过二级指针改变plist。
  2. 一开始有链表:当开始有链表,创建一个结构体指针tail,来找到最后一个节点,再将newnode赋给最后一个节点的next。

【数据结构】单向链表的增删查改以及指定pos位置的插入删除,数据结构,数据结构,链表

头插

头插分为两种情况,开始有链表和开始没有链表,但是两种情况不需要分类考虑,先将*pphead即plist赋给newnode->next,再将newnode连上*pphead。

【数据结构】单向链表的增删查改以及指定pos位置的插入删除,数据结构,数据结构,链表

尾删

 尾删分两种情况考虑:

  1. 只有一个节点:给*pphead赋空值
  2. 一个以上节点:确定尾节点tail后,通过tail的前一个节点tailprev,进行tailprev->next=NULL赋空值或者直接通过tail->next->next找倒数第二个节点,再给tail->next赋空值。

【数据结构】单向链表的增删查改以及指定pos位置的插入删除,数据结构,数据结构,链表

 头删

 头删不需要分情况,直接将第一个节点的next即第二个节点的地址通过newnode的中转赋给*pphead。【数据结构】单向链表的增删查改以及指定pos位置的插入删除,数据结构,数据结构,链表

 查找

创建一个结构体指针cur,链表中遍历查找cur->data==x的节点,找到后返回cur,方便后面的修改功能。

 (不需要修改,所以传入函数的是一级指针)

【数据结构】单向链表的增删查改以及指定pos位置的插入删除,数据结构,数据结构,链表

 在pos位置前插

 分两种情况考虑:

  1. 当pos为第一个节点,相当于头插,调用头插函数即可。
  2. 当pos不为第一个节点,通过pos的前一个节点prev,将newnode插入pos前面。 

​​​​​​【数据结构】单向链表的增删查改以及指定pos位置的插入删除,数据结构,数据结构,链表

 在pos位置后插

在pos位置后插,先将pos->next赋给newnode->next,把newnode和d3连上,再将newnode赋给pos->next,连上d2。

注意:在两个语句不能换位置,不然成环,循环打印

【数据结构】单向链表的增删查改以及指定pos位置的插入删除,数据结构,数据结构,链表

 删除pos位置

 分两种情况:

  1. pos在第一个节点位置,直接调用头删函数即可。
  2. pos不在第一个节点位置,通过pos的前一个节点prev,将pos->next赋给prev->next,达到将pos节点删除的效果。

 【数据结构】单向链表的增删查改以及指定pos位置的插入删除,数据结构,数据结构,链表

 删除pos的后一个位置

删除pos的后一个位置,需要先检测pos->next是否为空值,为空值就直接返回,若pos->next不为空赋给posNext,再将posNext->next赋给pos->next达到删除posNext节点,后面可以free(posNext)释放posNext节点,再posNext=NULL给它赋空值。

 【数据结构】单向链表的增删查改以及指定pos位置的插入删除,数据结构,数据结构,链表

无头删除pos位置

 不给头节点的情况下,可以先通过pos->data=posNext->data的方式交换内容,再删除pos的下一节点posNext,将pos替换为posNext,达到和删除pos一样的效果。

但是这种方法的缺点是当pos本身为尾节点时,不能通过下一节点posNext来使用替换法。

【数据结构】单向链表的增删查改以及指定pos位置的插入删除,数据结构,数据结构,链表

 

代码

【数据结构】单向链表的增删查改以及指定pos位置的插入删除,数据结构,数据结构,链表

总结

 在上面众多单向链表的实现中,很多并不实用,当需要大量的头插头删时,使用单向链表会更高效。

代码 

 SList.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>




typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

//typedef struct SListNode SLTNode;

//打印
void SLTPrint(SLTNode* phead);


SLTNode* BuySListNode(SLTDataType x);


//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);


//尾删
void SLTPopBack(SLTNode** pphead);


//头插
void SLTPushBack(SLTNode** pphead, SLTDataType);


//头删
void SLTPopFront(SLTNode** pphead);


//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);


//在pos位置前插
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);


//在pos位置后插
void SLTInsertAfter(SLTNode* pos, SLTDataType x);


//删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos);


//删除pos的后一个位置
void SLTEraseAfter(SLTNode* pos);

SList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"


//打印
void SLTPrint(SLTNode* phead)
{
	SLTNode* cur = phead;
	//while (cur != NULL)
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}



SLTNode* BuySListNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	newnode->data = x;
	newnode->next = NULL;

	return newnode;

}

尾插  phead是plist的形参   //开始就有链表
//void SLTPushBack(SLTNode* phead, SLTDataType x)
//{
//	SLTNode* newnode = BuySListNode(x);
//	SLTNode* tail = phead;
//	while (tail->next != NULL)
//	{
//		tail = tail->next;
//	}
//	tail->next = newnode;
//}

//尾插  //包括一开始没有链表
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySListNode(x);
	if (*pphead == NULL)
	{
		//改变结构体的指针,所以要用二级指针
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		//改变的结构体,用结构体的指针即可
		tail->next = newnode;
	}
}



//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySListNode(x);

	newnode->next = *pphead;
	*pphead = newnode;
}



//尾删
void SLTPopBack(SLTNode** pphead)
{
	//1.空
	assert(*pphead);
	//2、一个节点
	//3、一个以上节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		//方法1.
		SLTNode* tailPrev = NULL;
		SLTNode* tail = *pphead;
		while (tail->next)
		{
			tailPrev = tail;
			tail = tail->next;
		}
		free(tail);
		tailPrev->next = NULL;
		
		方法2.
		//SLTNode* tail = *pphead;
		//while (tail->next->next)
		//{
		//	tail = tail->next;
		//}
		//free(tail->next);
		//tail->next = NULL;
	}

}



//头删
void SLTPopFront(SLTNode** pphead)
{
	//空
	assert(*pphead);

	//非空
	SLTNode* newhead = (*pphead)->next;
	free(*pphead);
	*pphead = newhead;
}


//查找是否有x这个数,找到返回指向该数的指针
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}


//在pos位置前插
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pos);

	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuySListNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}


//在pos位置后插
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuySListNode(x);
	
	//下面两句不能交换位置,否则会成环
	newnode->next = pos->next;
	pos->next = newnode;
}


//删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pos);

	if (*pphead == pos)
	{
		SLTPopFront(pphead);
	}
	//else if (pos->next == NULL)
	//{
	//	SLTPopBack(pphead);
	//}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}		
		//free(prev->next);//不要free,不然这个节点后面全没了
		prev->next = pos->next;		
	}
}



//删除pos后一个位置
void SLTEraseAfter(SLTNode* pos)
{
	//
	assert(pos);

	//检测pos是否是尾节点
	//assert(pos->next);//暴力检测
	if (pos->next == NULL)//温和检测
	{
		return NULL;
	}

	SLTNode* posNext = pos->next;
	pos->next = posNext->next;
	free(posNext);
	posNext = NULL;

}

 Test.c文章来源地址https://www.toymoban.com/news/detail-743505.html

#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"


void TestSList1()
{
	int n;
	printf("请输入链表的长度:");
	scanf("%d", &n);
	printf("\n请依次输入每个节点的值:");
	SLTNode* plist = NULL;

	for (size_t i = 0; i < n; i++)
	{
		int val;
		scanf("%d", &val);
		SLTNode* newnode = BuySListNode(val);


		//头插
		newnode->next = plist;
		plist = newnode;

	}

	SLTPrint(plist);
	SLTPushBack(&plist, 1000);
	SLTPrint(plist);

}

void TestSList2()
{
	SLTNode* plist = NULL;
	
	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	//头插
	SLTPushFront(&plist, 10);
	SLTPushFront(&plist, 20);
	SLTPushFront(&plist, 30);
	SLTPushFront(&plist, 40);
	SLTPrint(plist);
}


void TestSList3()
{
	SLTNode* plist = NULL;

	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	头插
	//SLTPushFront(&plist, 10);
	//SLTPushFront(&plist, 20);
	//SLTPushFront(&plist, 30);
	//SLTPushFront(&plist, 40);
	//SLTPrint(plist);

	//尾删
	SLTPopBack(&plist);
	//SLTPopBack(&plist);
	//SLTPopBack(&plist);
	//SLTPopBack(&plist);
	//SLTPopBack(&plist);
	SLTPrint(plist);


}



void TestSList4()
{
	SLTNode* plist = NULL;

	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	//头插
	SLTPushFront(&plist, 10);
	SLTPushFront(&plist, 20);
	SLTPushFront(&plist, 30);
	SLTPushFront(&plist, 40);
	SLTPrint(plist);




	//头删
	SLTPopFront(&plist);
	SLTPrint(plist);
}


void TestSList5()
{
	SLTNode* plist = NULL;

	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	//头插
	SLTPushFront(&plist, 10);
	SLTPushFront(&plist, 20);
	SLTPushFront(&plist, 30);
	SLTPushFront(&plist, 40);
	SLTPrint(plist);


	//查找
	SLTNode* pos = SLTFind(plist, 40);
	if (pos)
	{
		pos->data *= 10;
	}
	SLTPrint(plist);
}

void TestSList6()
{
	SLTNode* plist = NULL;

	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	//头插
	SLTPushFront(&plist, 10);
	SLTPushFront(&plist, 20);
	SLTPushFront(&plist, 30);
	SLTPushFront(&plist, 40);
	SLTPrint(plist);

	//在pos位置前插
	int x;
	scanf("%d", &x);
	SLTNode* pos = SLTFind(plist, x);
	if (pos)
	{
		SLTInsert(&plist, pos, x * 10);
	}
	SLTPrint(plist);
}


void TestSList7()
{
	SLTNode* plist = NULL;

	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	//头插
	SLTPushFront(&plist, 10);
	SLTPushFront(&plist, 20);
	SLTPushFront(&plist, 30);
	SLTPushFront(&plist, 40);
	SLTPrint(plist);

	//在pos位置后插
	int x;
	scanf("%d", &x);
	SLTNode* pos = SLTFind(plist, x);
	if (pos)
	{
		SLTInsertAfter(pos, x * 10);
	}
	SLTPrint(plist);
}


void TestSList8()
{
	SLTNode* plist = NULL;

	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	//头插
	SLTPushFront(&plist, 10);
	SLTPushFront(&plist, 20);
	SLTPushFront(&plist, 30);
	SLTPushFront(&plist, 40);
	SLTPrint(plist);

	//删除pos位置
	int x;
	scanf("%d", &x);
	SLTNode* pos = SLTFind(plist, x);
	if (pos)
	{
		SLTErase(&plist, pos);
		pos = NULL;
	}
	SLTPrint(plist);
}



void TestSList9()
{
	SLTNode* plist = NULL;

	//尾插
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	//头插
	SLTPushFront(&plist, 10);
	SLTPushFront(&plist, 20);
	SLTPushFront(&plist, 30);
	SLTPushFront(&plist, 40);
	SLTPrint(plist);

	//删除pos后一个位置
	int x;
	scanf("%d", &x);
	SLTNode* pos = SLTFind(plist, x);
	if (pos)
	{
		SLTEraseAfter(pos);
		pos = NULL;
	}
	SLTPrint(plist);
}








void PrintSList(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}




int main()
{
	
	//TestSList1();
	// 头插 尾插
	//TestSList2();
	// 尾删
	//TestSList3();
	// 头删
	//TestSList4();
	// 查找
	//TestSList5();
	// pos位置前插
	//TestSList7();
	// pos位置后插
	//TestSList8();
	// 删除pos位置
	TestSList9();
	//删除pos的后一个位置
	//TestSList10();

	return 0;
}

到了这里,关于【数据结构】单向链表的增删查改以及指定pos位置的插入删除的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构入门(C语言)顺序表的增删查改

    本章会用C语言来描述数据结构中的顺序表,实现简单的增删查改操作,其中头文件包含在新建的头文件SeqList.h内,顺序表的实现在新建的Seqlist.c内,主函数Text.c将会实现菜单,方便我们进行功能的选择。 顺序表是用一段物理地址 连续 的存储单元依次存储数据元素的线性结构

    2024年02月03日
    浏览(38)
  • 【数据结构】单链表的增删查改(C语言实现)

    在上一节中我们提到了顺序表有如下缺陷: 在头部/中间的插入与删除需要挪动数据,时间复杂度为O(N),效率低; 增容需要申请新空间,可能会拷贝数据,释放旧空间,会有不小的消耗; 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容

    2024年02月06日
    浏览(36)
  • 【数据结构与算法】单链表的增删查改(附源码)

      这么可爱的猫猫不值得点个赞吗 😽😻 目录 一.链表的概念和结构 二.单链表的逻辑结构和物理结构 1.逻辑结构  2.物理结构 三.结构体的定义 四.增加 1.尾插   SListpushback 2.头插  SListpushfront 五.删除 1.尾删  SListpopback 2.头删  SListpopfront 六.查找  插入  释放   打印 1.查找

    2024年02月02日
    浏览(54)
  • 【数据结构.C】顺序表和单链表的增删查改

    宝子,你不点个赞吗?不评个论吗?不收个藏吗? 最后的最后,关注我,关注我,关注我,你会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要。 目录 单链表增删查改 c1.h sqlist.c number.c 单链表的增删查改  c1.h stuscore.c c1.h sqlist.c number.c  c1.h stuscore.c   宝子,你不点

    2024年02月11日
    浏览(91)
  • 【数据结构C/C++】单向链表的增删改查

    单向链表是比较常用的数据结构,最近再面试手撕算法的时候偶尔有遇到,所以就花了一点时间简单的写了一下C/C++版本的单向链表的代码。 这里我推荐使用C++版本,因为C++版本我特地优化了一下,提供了用户输入的功能,当然两个语言差异不大,注释可以直接看C版本的,比

    2024年02月07日
    浏览(33)
  • 数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)

    版本: 2024年4月25日 V1.0 发布于博客园 目录 目录 单向循环链表公式 初始化单向循环链表 构建单向循环链表结点 创建一个空链表(仅头结点) 创建一个新结点 插入数据 头插 中插 尾插 删除数据 头删 中删 尾删 查询打印数据 遍历打印 测试 测试结果: 完整代码 CircularLinkedLis

    2024年04月25日
    浏览(40)
  • C语言单向链表的增删操作

    2024年04月23日
    浏览(39)
  • 【数据结构入门】顺序表详解(增删查改)

    目录 顺序表的基本概念 动态顺序表的实现 初始化 插入 尾插法 头插法 指定位置之前插入 删除 尾删法 头删法 指定位置删除 查找 销毁 什么是顺序表? 顺序表是用一段 物理地址连续的存储单元 依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的

    2024年04月17日
    浏览(24)
  • 四、数据结构——单向链表的基本操作详解:创建、插入(头插法、尾插法、任意点插法)、删除(头删法、尾删法、任意位置删法)、查询(按值查下标、按下标查值)、遍历链表和清空链表

    ————后面附有全部代码———— 数据结构在计算机科学中扮演着重要角色,它用于组织和管理数据,提高数据的操作和访问效率。单向链表是一种简单但非常重要的数据结构。本文将深入探讨单向链表的定义、特点、基本操作。 单向链表是一种线性数据结构,由一系列

    2024年01月17日
    浏览(45)
  • 【从零开始写博客】链表运用:链表的增删查改及反转(day3)

    【数组】day2 【数组】day1 目录 链表概述 一、链表增删地初次理解 二、链表常见六个操作 三,链表的转置 总结 链表是通过指针将一个个节点串起来的数据结构,其优点是增删方便,灵活性强。以下将结合leetcode上的一些例题介绍链表的一些功能和应用。 相比数组依靠覆盖来

    2024年02月15日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包