Bootstrap

线性表单链表的基本操作:添加、插入、删除、查找(非常全面,C语言实现)

前言

链表是一种物理存储单元上非连续、非顺序的存储结构,由一系列结点组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

一、链表是什么?

1.概念

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。

2.链表的组成

每个链表节点包含两个部分:存储数据元素的数据域和存储下一个节点地址的指针域。节点中的数据可以是任何类型,如整数、字符、浮点数等。此外,链表有一个头节点,它指向链表中的第一个节点。最后一个节点则指向NULL,表示链表的结束。

2.链表的优点与缺点

链表的主要优势在于它可以灵活地管理长度或数量不确定的数据,对于这种逐渐增加且不定长的数据,使用链表可以节省内存。当需要增加新数据时,链表可以动态地申请内存,避免了一次性分配大量空间可能造成的浪费。另外,链表并不需要按照序号对数据进行随机访问。

然而,相比于数组,链表在访问数据时可能耗费更多的时间,因为访问元素可能需要遍历整个链表。尽管如此,链表在插入和删除数据方面的效率较高,因为这些操作仅需要修改指针所指向的区域,不需要进行大量的数据移动操作。

二、单链表的创建;插入(头插、尾插);删除(头删、尾删、指点元素删除);查找

1.单链表的存储结构

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

typedef int SLTDateType;//这里用typedef声名int类型,是方便后续修改为其它类型
typedef struct SListNode {
	SLTDateType data;
	struct SListNode* next;
}SLTNode;

2.创建一个节点

SLTNode* BuyListNode(SLTDateType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;

}

3.插入元素 (尾插、头插)和 指定位置插入

void SListPushBack(SLTNode** pphead, SLTDateType x)//尾插
{

	SLTNode* newnode = BuyListNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
	
	
}


void SListPushFront(SLTNode** pphead, SLTDateType x)//头插
{
	SLTNode* newnode = BuyListNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		newnode->next = *pphead;
		*pphead = newnode;
	}
}


void SListInsertAfter(SLTNode* pos, SLTDateType x)//在pos位置后面插入元素
{
	assert(pos->next);
	SLTNode* newnode = BuyListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

4.删除节点(尾删、头删)和删除指定位置

void SListPopBack(SLTNode** pphead)//尾删
{
	assert(pphead);
	if (*pphead == NULL)
	{
		return;
	}
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* tail = *pphead;
		SLTNode* prev = NULL;
		while (tail->next)
		{
			prev = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;
		prev->next = NULL;
	}
}


void SListPopFront(SLTNode** pphead)//头删
{
	assert(*pphead != NULL);
	SLTNode* newhead = (*pphead)->next;
	free(*pphead);
	*pphead = newhead;
}



void SListErase(SLTNode** pphead, SLTNode* pos)//删除掉指定位置
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		*pphead = pos->next;
		free(pos);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);

	}
}

5.查找节点

SLTNode* SListFind(SLTNode* phead, SLTDateType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (x == cur->data)
		{
			return cur;
		}
		else
		{
			cur = cur->next;
		}
	}
	return NULL;
}

6.销毁所有节点

void SListDestory(SLTNode** pphead)//销毁
{
	assert(*pphead);
	SLTNode* cur = *pphead;
	while (cur)
	{
		SLTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
	printf("销毁成功");
}

7.打印所有节点

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

8.主函数

test1()
{
	SLTNode* plist = NULL;
	printf("    尾插:");
	SListPushBack(&plist, 4);
	SListPushBack(&plist, 1);
	SListPushBack(&plist, 2);
	SListPushBack(&plist, 7);
	SListPushBack(&plist, 8);
	SListPushBack(&plist, 9);
	SListPushBack(&plist, 3);
	SListPushBack(&plist, 5);//尾插
	SListPrint(plist);

	printf("    头插:");
	SListPushFront(&plist, 11);//头插
	SListPrint(plist);

	printf("    尾删:");
	SListPopBack(&plist);
	SListPrint(plist);

	printf("    头删:");
	SListPopFront(&plist);
	SListPrint(plist);


	printf("查找元素:");
	SLTNode* k=SListFind(plist, 2);
	//这里函数调用后,查找到会返回一个指针,表示查找到的位置。如果打印的话,返回指针位置的后续节点也会打印出来
	SListPrint(k);

	printf("销毁链表:");
	SListDestory(&plist);//销毁链表

}

test2() 
{
	SLTNode* plist = NULL;
	printf("         尾插:");
	SListPushBack(&plist, 4);
	SListPushBack(&plist, 1);
	SListPushBack(&plist, 2);
	SListPushBack(&plist, 7);
	SListPushBack(&plist, 8);
	SListPushBack(&plist, 9);
	SListPushBack(&plist, 3);
	SListPushBack(&plist, 5);//尾插
	SListPrint(plist);


	printf("     查找元素:");
	SLTNode* k = SListFind(plist, 8);//这里输入需要查找的元素8,返回存储8的地址的指针
	//这里函数调用后,查找到元素会返回一个指针
	printf("  我找到了元素%d,函数调用后我返回了记录%d位置的指针k \n", k->data, k->data);//看一下找到没?找到了,位置返回正确
	

	printf("指定位置k插入:");
	SListInsertAfter(k, 19);
	SListPrint(plist);

	printf("指定位置k删除:");//这里用开始返回的k指针
	SListErase(&plist,k);//删除掉指定位置(也就是删除8)
	SListPrint(plist);//可以看到8已经被删除了



}
int main()
{
	test1();
	//test2();//这里测试:删除指定位置;指定位置(地址)后面插入
	return 0;
}

9.完整代码(含test1和test2,都可以进行测试)

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

typedef int SLTDateType;//这里用typedef声名int类型,是方便后续修改为其它类型
typedef struct SListNode {
	SLTDateType data;
	struct SListNode* next;
}SLTNode;




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



SLTNode* BuyListNode(SLTDateType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;

}


void SListPushBack(SLTNode** pphead, SLTDateType x)//尾插
{

	SLTNode* newnode = BuyListNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
	
	
}



void SListPushFront(SLTNode** pphead, SLTDateType x)//头插
{
	SLTNode* newnode = BuyListNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		newnode->next = *pphead;
		*pphead = newnode;
	}
}


void SListPopBack(SLTNode** pphead)//尾删
{
	assert(pphead);
	if (*pphead == NULL)
	{
		return;
	}
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* tail = *pphead;
		SLTNode* prev = NULL;
		while (tail->next)
		{
			prev = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;
		prev->next = NULL;
	}
}


void SListPopFront(SLTNode** pphead)//头删
{
	assert(*pphead != NULL);
	SLTNode* newhead = (*pphead)->next;
	free(*pphead);
	*pphead = newhead;
}



SLTNode* SListFind(SLTNode* phead, SLTDateType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (x == cur->data)
		{
			return cur;
		}
		else
		{
			cur = cur->next;
		}
	}
	return NULL;
}


void SListInsertAfter(SLTNode* pos, SLTDateType x)//在pos位置后面插入元素
{
	assert(pos->next);
	SLTNode* newnode = BuyListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}


void SListErase(SLTNode** pphead, SLTNode* pos)//删除掉指定位置
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		*pphead = pos->next;
		free(pos);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);

	}
}

void SListDestory(SLTNode** pphead)//销毁
{
	assert(*pphead);
	SLTNode* cur = *pphead;
	while (cur)
	{
		SLTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
	printf("销毁成功\n");

}







test1()
{
	SLTNode* plist = NULL;
	printf("    尾插:");
	SListPushBack(&plist, 4);
	SListPushBack(&plist, 1);
	SListPushBack(&plist, 2);
	SListPushBack(&plist, 7);
	SListPushBack(&plist, 8);
	SListPushBack(&plist, 9);
	SListPushBack(&plist, 3);
	SListPushBack(&plist, 5);//尾插
	SListPrint(plist);

	printf("    头插:");
	SListPushFront(&plist, 11);//头插
	SListPrint(plist);

	printf("    尾删:");
	SListPopBack(&plist);
	SListPrint(plist);

	printf("    头删:");
	SListPopFront(&plist);
	SListPrint(plist);


	printf("查找元素:");
	SLTNode* k=SListFind(plist, 2);
	//这里函数调用后,查找到会返回一个指针,表示查找到的位置。如果打印的话,返回指针位置的后续节点也会打印出来
	SListPrint(k);

	printf("销毁链表:");
	SListDestory(&plist);//销毁链表

}

test2() 
{
	SLTNode* plist = NULL;
	printf("         尾插:");
	SListPushBack(&plist, 4);
	SListPushBack(&plist, 1);
	SListPushBack(&plist, 2);
	SListPushBack(&plist, 7);
	SListPushBack(&plist, 8);
	SListPushBack(&plist, 9);
	SListPushBack(&plist, 3);
	SListPushBack(&plist, 5);//尾插
	SListPrint(plist);


	printf("     查找元素:");
	SLTNode* k = SListFind(plist, 8);//这里输入需要查找的元素8,返回存储8的地址的指针
	//这里函数调用后,查找到元素会返回一个指针
	printf("  我找到了元素%d,函数调用后我返回了记录%d位置的指针k \n", k->data, k->data);//看一下找到没?找到了,位置返回正确
	

	printf("指定位置k插入:");
	SListInsertAfter(k, 19);
	SListPrint(plist);

	printf("指定位置k删除:");//这里用开始返回的k指针
	SListErase(&plist,k);//删除掉指定位置(也就是删除8)
	SListPrint(plist);//可以看到8已经被删除了



}
int main()
{
	test1();
	//test2();//这里测试:删除指定位置;指定位置(地址)后面插入
	return 0;
}

关注博主。有不懂的可以直接问我,看到消息后我会及时回复!!!

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;