数据结构——实现单向链表

这篇具有很好参考价值的文章主要介绍了数据结构——实现单向链表。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🐮前言

  • 单链表是一种常见的数据结构,用于存储一系列的数据元素,每个节点包含数据和指向下一个节点的指针。

  • 单链表通常用于实现某些算法或数据结构,如链式前向星、哈希表、链式栈、队列等等。

  • 单链表在程序设计中的作用不可忽略,是很多基础算法的核心数据结构之一。

  • 学习单链表有助于提高算法和数据结构的基本能力并增强编程的实践经验。

  • 本篇博客将介绍单链表的基本操作及其算法应用,旨在帮助读者掌握单链表数据结构及相关算法的设计和实现,进一步提高编程的能力和水平。

总之,单链表是一种常见的基础数据结构,与编程和算法设计密切相关,了解和掌握单链表的基本概念和操作,对于提高编程能力和设计程序算法都有帮助。

🍌单链表与顺序表的对比

数据结构——实现单向链表

单链表的优点:

  • 动态性:单链表可以在任意位置进行插入和删除操作,不必像顺序表那样需要移动元素,操作比较灵活。
  • 空间利用效率高:单链表的结构只需要记录一个指针域和一个数据域,不像顺序表需要预留一定的存储空间,因此空间利用率较高。

单链表的缺点:

  • 存储空间分配不灵活:由于单链表的结构决定了只有通过指针才能访问相邻元素,因此不能随机访问。
  • 存储密度较低:由于每个结点只包含一个指针域和一个数据域,因此存储密度比较低,会占用更多的空间。

顺序表的优点:

  • 存储密度较高:由于所有元素在连续的存储空间中,因此存储密度比较高,可以节省空间。
  • 存取效率高:由于所有元素在连续的存储空间中,因此可以通过元素的下标进行随机存取,存取效率比较高。

顺序表的缺点:

  • 插入和删除操作较慢:由于需要移动元素,因此插入和删除操作比较慢。
  • 维护困难:当顺序表达到一定的长度后,插入和删除操作会变得更加困难,在需要频繁进行插入和删除操作时,顺序表的效率会比较低。

总的来说,单链表和顺序表各有优点和缺点,需要根据具体的应用场景进行选择。如果需要频繁进行插入和删除操作,单链表的效率更高;如果需要频繁进行随机存取操作,顺序表更为适合。
数据结构——实现单向链表

🍊单链表的初始操作及结构体

  • 单链表的实现也是需要搭建3个文件,一个是SList.h(头文件),SList.c(各函数的实现文件),Test.c(测试文件)。
  • 搭建好之后我们只需要在SList.cTest.c文件开头包含#include"SList.h"即可将三个文件链接起来。
  • 写单链表的结构体时,需要定义包含两个成员的结构体类型,一个成员用于存储结点的数据,另一个成员用于存储下一个结点的指针。一般而言,结构体类型的名称和结构体变量的名称都需要有意义,以便于程序的阅读和理解。
    相关功能代码:
#pragma once
// 输入输出所需头文件
#include<stdio.h>
// malloc 所需头文件
#include<stdlib.h>
// assert 所需头文件
#include<assert.h>

// 每个节点的数据的类型
typedef int SLTDataType;

// 每个节点的结构体
typedef struct SListNode
{
	// 存放该结点的数据
	SLTDataType data;
	// 存放下一个节点的地址,将整个结构串联成一个单链表
	struct SListNode* next;
}SLTNode;  // 用 typedef 将结构体重命名为 SLTNode 便于后续写程序 

🍉申请一个节点

  • 单链表的节点是单链表中最基本的单位。每个节点由两部分组成,分别是数据域和指针域。数据域存储节点的数据或者信息,而指针域指向下一个节点的地址。因此,单链表是由一连串的节点构成的数据结构。具体来说,单链表的节点通常包含以下信息:

  • 1.数据域:存储节点的数据或信息,可以是任何数据类型,例如整数、字符、字符串、结构体等。

  • 2.指针域:指向下一个节点的地址。在C语言中可以使用结构体来表示一个节点,节点结构体至少包含一个数据项和一个指向下一个节点的指针

单链表的节点是非常灵活和可扩展的,因为每个节点都只需要存储自身的信息和指向下一个节点的指针就可以了,这就使得单链表更易于被实现和扩展。当需要插入或删除节点时,只需更新相应节点的指针域即可。
同时,这种设计也带来了一定的缺点,即单链表不能直接访问任何一个节点的前一个节点。

  • 节点应至少包括一个数据项(例如整数或字符串)和一个指向下一个节点的指针。
  • 申请内存要创建一个新的节点,你需要使用C语言的stdlib.h库中的malloc函数来为其分配内存。将分配一个大小为SListNode结构体的内存块,并将其指针指向newnode。在这个节点被使用完毕之后,应该使用free函数释放它的内存。
  • 经过内存分配后,你需要用正确的值初始化节点。在这种情况下,节点的值可以作为函数的参数进行传递。初始化一个新的节点并返回这个节点的指针。
  • 我们首先为节点分配内存,然后将value赋值给节点的data字段,并把next设为NULL(因为这个节点尚未链接到另一个节点上)。

这样,我们就成功地创建了一个新的节点,并初始化了它的数据元素和指向下一个节点的指针。


SLTNode* BuyLTNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

🥕打印

  • 单链表的打印操作是指遍历单链表并输出其中所有节点的数据或信息,这是单链表中常用的一种操作,也是单链表中尤为基础的一部分。
  • 定义一个指针变量,指向单链表的头节点,命名为cur。其中,head为单链表头节点的指针。
  • 使用while循环遍历整个单链表,直到当前的指针变量为空。
  • 在循环中,使用p指针变量访问当前节点(即p所指向的节点),并打印其数据或信息。在实际操作中,可以根据需要定制输出样式。
  • 将指针变量p更新为下一个节点的地址,即p = p->next,继续访问下一个节点。直到循环结束,所有的节点都被遍历,并输出了其中所有的数据或信息。
    相关功能代码:
void SLPrint(SLTNode* phead)
{
    struct Node* cur = phead; // 定义指针变量,指向头节点
    while(cur != NULL){ // 循环条件
        printf("%d ", cur->val); // 输出节点数据或信息
        cur = cur->next; // 修改指针变量,指向下一个节点
    }
}

需要注意的是,单链表的打印操作在多种算法或数据结构中都有应用。
同时,其中包含单个强迫离散节点间转移到下一个节点的元素。其执行步骤、方式及相关内容会因场景而异,需要结合实际情况进行设计。

🍓销毁

  • 单链表的销毁是指将单链表中的所有节点都删除,并将链表中的所有内存空间释放
  • 具体步骤:
  • 1.定义一个指针变量pos来保存待删除节点的下一个节点。
  • 2.使用while循环遍历整个单链表,直到当前指针plist为空。
  • 3.在循环中,保存当前节点的下一个节点的指针,即pos = pos->next。
  • 4.使用free函数释放当前节点的内存空间,即free(head),释放节点所占用的内存空间。
  • 5.将指针head指向下一个节点。即plist = pos
    重复步骤3-5,直到整个单链表中的所有节点都被删除并释放了内存空间。最后在返回。
  • 需要注意的是,有指针就别忘了要assert
  • 需要注意的是,在进行单链表的尾插操作时,需要保证单链表不为空。可以在函数外创建一个头节点,排除空链表情况,并将其传入SLPushBack函数中进行操作。另外,为新节点分配内存空间之后,也需要对内存申请情况进行检查,以避免发生内存泄漏等问题。
    相关程序代码:
void SLDestory(SLTNode* plist,SLTNode* pos)
{
	assert(plist);

	while (pos)
	{
		plist = pos;
		pos = pos->next;
		free(plist);
		plist->next = NULL;
	}
	return;
}

还需要注意的是,在使用上述函数时,需要首先保证单链表中所有节点都已经被访问或使用,否则可能会造成内存泄漏。

🍎尾插

  • 单链表尾插是单链表中的一种常用操作,而且非常实用,它可以在单链表的末尾插入一个新节点。
  • 找到单链表的尾部节点,即包含指针域值为NULL的节点。可以用一个循环来找到它。
  • 创建一个新节点,将其数据放入其中。需要调用BuyLTNode函数为新节点分配内存空间。
  • 将新节点连接到单链表的尾部节点上,即将尾部节点的指针域指向新节点。至此,新的节点已经成功插入到了单链表的末尾。
  • 为新节点分配内存空间之后,也需要对内存申请情况进行检查(assert),以避免发生内存泄漏等问题。
    相关程序代码:
void SLPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);
	assert(*pphead);
	//1,空链表
	//2,非空链表
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		tail->next = newnode;
	}
}

🍐尾删

  • 单链表尾删是指删除单链表中的尾节点,使其前一个节点成为新的尾节点。
  • 找到单链表的倒数第二个节点。可以使用一个循环遍历直到找到该节点。注意,需要判断单链表中是否有节点,否则删除操作无法进行
  • 保存单链表尾节点的指针,以便后续释放它所占用的内存空间。
  • 将尾节点从单链表中删除,即将p节点的指针域设置为NULL
  • 释放单链表尾节点占用的内存空间。
    相关程序代码:
void SLPopBack(SLTNode** pphead)
{
	//assert(pphead);   //链表为空,pphead也不能为空,因为他是头指针plist的地址
	assert(*pphead);  //链表为空,不能头删
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* tail = *pphead;
		//找尾
		while (tail->next->next)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

需要注意的是,在进行单链表的尾删操作时,需要先对单链表进行判空处理,避免出现访问空指针的错误。

🍇头插

  • 单链表头插是指在单链表的头部插入一个新的节点,使其成为新的头节点。
  • 创建一个新的节点,并将新节点的指针域指向原来的头节点。需要调用BuyLTNode函数为新节点分配内存空间。
  • 将头指针指向新节点,即将头指针修改为新节点的地址。
    相关程序代码:
void SLPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);

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

需要注意的是,在进行单链表的头插操作时,需要先对头指针进行检查,避免出现空指针的错误。此外,在新建节点并为其分配内存空间时,也需要进行内存申请情况的检查,以避免出现内存泄漏等问题。

🍑头删

  • 单链表头删是指删除单链表中的头节点,使其后一个节点成为新的头节点。
  • 保存单链表头节点的指针,以便后续释放它所占用的内存空间。
  • 释放原来的头节点所占用的内存空间。
    相关程序代码:
void SLPopFront(SLTNode** pphead)
{
	//assert(pphead);   //链表为空,pphead也不能为空,因为他是头指针plist的地址
	assert(*pphead);  //链表为空,不能头删。

	SLTNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
}

需要注意的是,在进行单链表的头删操作时,需要先对头指针进行检查,避免出现空指针的错误。此外,在释放原来的头节点所占用的内存空间时,也需要进行内存申请情况的检查,以避免出现内存泄漏等问题。

🍍数据的查找

  • 在单链表中查找数据通常需要遍历整个链表,找到匹配的节点并返回其位置或指针。
  • 使用一个指针指向链表的头结点,依次遍历链表中的每一个节点。
  • 在每个节点中,检查该节点中存储的元素是否与待查找元素相同。如果相同,则返回该节点的位置或指针。
  • 如果遍历整个链表都找不到相匹配的节点,则返回NULL表示查找失败。
    相关程序代码:

SLTNode* SLFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}

	return NULL;
}
需要注意的是,在进行单链表中数据查找操作时,需要先对单链表进行判空处理,避免出现访问空指针的错误。 此外,还需注意的是,本算法只能查找链表中第一个匹配的元素,无法查找所有匹配的元素。

🍋数据的修改

  • 在单链表中修改指定节点的数据,通常需要先通过遍历找到该节点,之后直接修改其存储的数据。
  • 使用一个指针指向链表的头结点,依次遍历链表中的每一个节点。
  • 在每个节点中,检查该节点中存储的元素是否与待修改元素相同。如果相同,则直接修改该节点中存储的数据。
  • 如果遍历整个链表都找不到匹配的节点,则返回NULL表示操作失败。
    相关程序代码:
SLTNode* SLModify(SLTNode* phead, int target, int newdata) 
{
	SLTNode* cur = phead;
	while (cur != NULL) {
		if (cur->data == target) {
			cur->data = newdata;
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

需要注意的是,在进行单链表中数据修改操作时,需要先对单链表进行判空处理,避免出现访问空指针的错误。此外,本算法只能修改链表中第一个匹配的元素,无法修改所有匹配的元素。

🍅在pos位置之后插入节点

  • 首先对pos进行判空操作。
  • 创建一个新节点 newnode,调用BuyLTNode函数。
  • newnodenext指向pos位置的next,在用posnext指向newnode
    相关程序代码:
//在pos之后插入
void SLInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuyLTNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

🥔在pos位置之前插入节点

  • pos位置之前插入,因为单链表具有单向性,因此这里需要遍历单链表找到pos位置的前一个节点,才能进行插入。
  • 但是你会发现,如果是pos刚好指向头结点就可以直接用头插。
  • 因为这里调用了头插,所以这里也要使用二级指针来操作。
    相关程序代码:
//在pos之前插入
void SLInsertFront(SLTNode** pphead,SLTNode* pos,SLTDataType x)
{
	assert(pphead);
	assert(pos);
	//如果pos为第一个节点,直接调用前面的头插
	if (*pphead == pos)
	{
		SLPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuyLTNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}

🐱删除pos位置之后的节点

  • 找到要删除节点的位置。
  • 将要删除节点的 next 指向NULL
  • 找到前一个节点,将其next指向NULL
  • 释放要删除节点及其后继节点内存空间。
    相关程序代码:
void SLEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);

	SLTNode* next = pos->next;
	pos->next = next->next;
	free(next);
}

🐶删除pos位置之前的节点

  • 首先断言(assert),然后再调用头删(SLPopFront).
  • 之后再将 prevnext 指向要删除节点的next
  • 释放要删除节点的内存空间。
  • 释放要删除及其前面的节点。
    相关程序代码:
void SLEraseFront(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);

	if (pos == *pphead)
	{
		SLPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}

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

🐒完整代码

SList.h

#pragma once
// 输入输出所需头文件
#include<stdio.h>
// malloc 所需头文件
#include<stdlib.h>
// assert 所需头文件
#include<assert.h>

// 每个节点的数据的类型
typedef int SLTDataType;

// 每个节点的结构体
typedef struct SListNode
{
	// 存放该结点的数据
	SLTDataType data;
	// 存放下一个节点的地址,将整个结构串联成一个单链表
	struct SListNode* next;
}SLTNode;  // 用 typedef 将结构体重命名为 SLTNode 便于后续写程序 

//申请一个节点(包含初始化)
SLTNode* BuyLTNode(SLTDataType x);

//单链表的打印
void SLTPrint(SLTNode* phead);

//头插节点
void SLPushFront(SLTNode** pphead, SLTDataType x);

//尾插节点
void SLPushBack(SLTNode** pphead, SLTDataType x);

//头删节点
void SLPopFront(SLTNode** pphead);

//尾删节点
void SLPopBack(SLTNode** pphead);

//节点的查找
SLTNode* SLFind(SLTNode* phead, SLTDataType x);

//节点的修改
SLTNode* SLModify(SLTNode* phead, int target, int newdata);

//pos位置之前插入节点
void SLInsertFront(SLTNode** pphead, SLTNode* pos, SLTDataType x);

//pos位置之后插入节点
void SLInsertAfter(SLTNode* pos, SLTDataType x);

//pos位置之前删除节点
void SLEraseFront(SLTNode** pphead, SLTNode* pos);

//pos位置之后删除节点
void SLEraseAfter(SLTNode* pos);

//节点的销毁
void SLDestory(SLTNode* plist, SLTNode* pos);

SList.c

#include"SList.h"

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

//申请一个节点(包含初始化)
SLTNode* BuyLTNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

//头插节点
void SLPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);

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

//尾插节点
void SLPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);
	assert(*pphead);
	//1,空链表
	//2,非空链表
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		tail->next = newnode;
	}
}

//头删节点
void SLPopFront(SLTNode** pphead)
{
	//assert(pphead);   //链表为空,pphead也不能为空,因为他是头指针plist的地址
	assert(*pphead);  //链表为空,不能头删。

	SLTNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
}

//尾删节点
void SLPopBack(SLTNode** pphead)
{
	//assert(pphead);   //链表为空,pphead也不能为空,因为他是头指针plist的地址
	assert(*pphead);  //链表为空,不能头删
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* tail = *pphead;
		//找尾
		while (tail->next->next)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

//查找单链表的节点
SLTNode* SLFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}

	return NULL;
}

//修改单链表的节点
SLTNode* SLModify(SLTNode* phead, int target, int newdata) 
{
	SLTNode* cur = phead;
	while (cur != NULL) {
		if (cur->data == target) {
			cur->data = newdata;
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//在pos之前插入节点
void SLInsertFront(SLTNode** pphead,SLTNode* pos,SLTDataType x)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SLPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuyLTNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}


//在pos之后插入节点
void SLInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuyLTNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}


 //删除pos位置之前的节点
void SLEraseFront(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);

	if (pos == *pphead)
	{
		SLPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}

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

//删除pos位置之后的节点
void SLEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);

	SLTNode* next = pos->next;
	pos->next = next->next;
	free(next);
}


//单链表的销毁
void SLDestory(SLTNode* plist,SLTNode* pos)
{
	assert(plist);

	while (pos)
	{
		plist = pos;
		pos = pos->next;
		free(plist);
		plist->next = NULL;
	}
	return;
}

Test,c


#include"SList.h"

void TestSList1()
{
	SLTNode* plist = NULL;
	SLPushFront(&plist, 1);
	SLPushFront(&plist, 2);
	SLPushFront(&plist, 3);
	SLPushFront(&plist, 4);
	SLPushFront(&plist, 5);
	SLPrint(plist);

	SLPushBack(&plist, 1);
	SLPushBack(&plist, 2);
	SLPushBack(&plist, 3);
	SLPushBack(&plist, 4);

	SLPrint(plist);

	SLPushBack(&plist, 5);

	SLPrint(plist);

	SLPopBack(&plist, 1);
	SLPopBack(&plist, 2);
	SLPopBack(&plist, 3);
	SLPopBack(&plist, 4);
	SLPopBack(&plist, 5);

	SLPrint(plist);

	SLPopFront(&plist, 1);
	SLPopFront(&plist, 2);
	SLPopFront(&plist, 3);
	SLPopFront(&plist, 4);

	SLPrint(plist);

}

void TestSList2()
{
	SLTNode* plist = NULL;
	SLPushFront(&plist, 1);
	SLPushFront(&plist, 2);
	SLPushFront(&plist, 3);
	SLPushFront(&plist, 4);
	SLPushFront(&plist, 5);
	SLPushFront(&plist, 6);
	SLPushFront(&plist, 7);
	SLPrint(plist);


	SLModify(plist, 1, 999);
	SLPrint(plist);
	SLModify(plist, 2, 999);
	SLPrint(plist); 
	SLModify(plist, 3, 999);
	SLPrint(plist); 
	SLModify(plist, 4, 999);
	SLPrint(plist);
	SLModify(plist, 5, 999);
	SLPrint(plist);
	SLModify(plist, 6, 999);
	SLPrint(plist);
	SLModify(plist, 7, 999);
	SLPrint(plist);
}

void TestSList3()
{
	SLTNode* plist = NULL;
	SLPushFront(&plist, 1);
	SLPushFront(&plist, 2);
	SLPushFront(&plist, 3);
	SLPushFront(&plist, 4);
	SLPushFront(&plist, 5);
	SLPushFront(&plist, 6);
	SLPushFront(&plist, 7);
	SLPrint(plist);


	SLFind(&plist, 3);
	SLPrint(plist);
}
int main()
{
	//TestSList1();
	//TestSList2();
	TestSList3();
	return 0;
}

🐘写在最后

单链表是一种与数组相对的数据结构,在实际的开发中很常见。它虽然不能像数组那样随机访问,但它具有动态的特点,可以高效地进行插入和删除操作。了解单链表的实现方式和使用方法,有助于我们在实际开发中更加灵活地运用它。

在本篇博客中,我们介绍了单链表的基本知识,包括如何在单链表中插入节点和删除节点。
需要注意的是,在单链表操作的过程中,对指针的操作十分关键,需要谨慎地操作。

感谢各位阅读本小白的博客,希望能帮助到大家!也请大家严厉指出并纠正我在文章中的错误。😄文章来源地址https://www.toymoban.com/news/detail-466186.html

到了这里,关于数据结构——实现单向链表的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【数据结构初阶】三、 线性表里的链表(无头+单向+非循环链表 -- C语言实现)

    ========================================================================= 相关代码gitee自取 : C语言学习日记: 加油努力 (gitee.com)  ========================================================================= 接上期 : 【数据结构初阶】二、 线性表里的顺序表(C语言实现顺序表)-CSDN博客  =========================

    2024年02月08日
    浏览(56)
  • 【数据结构】单向链表

    哈喽,大家好,今天我们学习的是数据结构里的链表,这里主要讲的是不带哨兵卫头节点的单向链表,下篇将会继续带大家学习双向链表。 目录 1.链表的概念 2.单向链表接口的实现 2.1动态申请一个节点 2.2单链表打印 2.3单链表尾插 2.4单链表头插 2.5单链表尾删 2.6单链表头删

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

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

    2024年04月25日
    浏览(51)
  • 数据结构入门(C语言版)线性表中链表介绍及无头单向非循环链表接口实现

    概念 : 线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素 。因此,为了表示每个数据元素与其直接后继数据元素之间的逻辑关系,对数据元素来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。这

    2023年04月09日
    浏览(48)
  • 数据结构与算法(三):单向链表

    链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑是通过链表种的指针链接次序实现的。链表由一系列节点组成,每个节点包括两部分:一个是存储数据元素的数据域,一个是存储下一个节点地址的指针域。单向链表从头节点(也可以没有头节点)开始

    2024年02月15日
    浏览(53)
  • 【数据结构】动图详解单向链表

    目录 1.什么是链表         1.问题引入         2. 链表的概念及结构         3. 问题解决 2.单向链表接口的实现         1.接口1,2---头插,尾插         2. 接口3,4---头删,尾删         3. 接口5---查找          4. 接口6,7---插入,删除         5. 接口

    2024年01月18日
    浏览(56)
  • 【数据结构篇】手写双向链表、单向链表(超详细)

    什么是链表 ? 链表(Linked List)是用链式存储结构实现的线性表。链表示意图: 链表的组成 : 数据域 + 引用域 (数据域和引用域合称结点或元素) 数据域存放数据元素自身的数据 引用域存放相邻结点的地址 链表的特点 : 链表中元素的联系依靠引用域 具有线性结构的特

    2024年02月11日
    浏览(41)
  • 数据结构——单向链表(C语言版)

    在数据结构和算法中,链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。在C语言中,我们可以使用指针来实现单向链表。下面将详细介绍如何用C语言实现单向链表。 目录 1. 定义节点结构体 2. 初始化链表 3. 插入节点 4. 删除节点

    2024年03月24日
    浏览(43)
  • 数据结构:线性表之-单向链表(无头)

    目录 什么是单向链表 顺序表和链表的区别和联系 顺序表: 链表: 链表表示(单项)和实现 1.1 链表的概念及结构 1.2单链表(无头)的实现 所用文件 将有以下功能: 链表定义 创建新链表元素 尾插 头插 尾删 头删 查找-给一个节点的指针 改 pos位置之前插入 删除pos位置的值 成品

    2024年02月09日
    浏览(66)
  • 数据结构《链表》无头单向非循环-动图详解

    前面学习了顺序表发现,顺序表虽然好,但也有很多不足的地方,比方说,顺序表是一块连续的物理空间,如果头插或者头删,那么整个数组的数据都要移动。但是链表不一样,链表是通过指针访问或者调整,链表是物理空间是不连续的,通过当前的next指针找到下一个。 插

    2024年02月06日
    浏览(48)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包