资讯专栏INFORMATION COLUMN

C语言实现单链表

cpupro / 1079人阅读

摘要:文章目录一单链表与顺序表的区别二关于链表中的一些函数接口的作用及实现头文件里的结构体和函数声明等等尾插尾删头插头删单链表查找中间插入在后面进行插入中间删除在后面进行删除多带带打印链表和从头到尾打印链表


一、单链表与顺序表的区别:

一、顺序表:

1、内存中地址连续

2、长度可以实时变化

3、不支持随机查找

4、适用于访问大量元素的,而少量需要增添/删除的元素的程序

5、中间插入或者删除比较方便,内存命中率较高

二、链表

1、内存中地址不连续(逻辑上连续,物理上不连续)

2、长度可以实时变化(避免浪费空间)

3、不支持随机查找,查找的时间复杂度为o(1),

4、适用于访问大量元素的,对访问元素无要求的程序

5、中间插入或者删除比较方便,效率高

二、关于链表中的一些函数接口的作用及实现

1、创建接口,开辟空间

2、尾插尾删

3、头插头删

4、查找并修改

5、中插中删

ps:我看了许多的单链表文章,在插删的接口实现上大多数是往前进行插删,这里写的则是往后进行插删

1、头文件里的结构体和函数声明等等

#pragma once#define _CRT_SECURE_NO_WARNINGS#include#include#includetypedef int SListDataType;//节点typedef struct SListNode{	SListDataType data;	struct SListNode* next;}SListNode;//struct SList//{//	SListNode* head;//	SListNode* tail;//};//尾插尾删void SListPushBack(SListNode** pphead, SListDataType x);void SListPopBack(SListNode** pphead);//头插头删void SListPushFront(SListNode**  pphead, SListDataType x);void SListPopFront(SListNode** pphaed);void SListPrint(SListNode* phead);//查找并修改SListNode* SListFind(SListNode* phead, SListDataType x);//中插中删void SListInserAfter(SListNode**pphead,SListNode* pos, SListDataType x);void SListEraseAfter(SListNode* pos);//从头到尾打印链表void PrintTailToHead(SListNode* pList);

2、创建接口空间

//开辟的下一个空间SListNode* BuySListNode(SListDataType x){	SListNode* newNode = (SListNode*)malloc(sizeof(SListNode));	if (newNode == NULL)	{		printf("申请结点失败/n");		exit(-1);	}	newNode->data = x;	newNode->next = NULL;	return newNode;}

3.尾插尾删

//尾插void SListPushBack(SListNode** pphead, SListDataType x){	SListNode* newNode = BuySListNode(x);//我们指向头指针的那个结点是**pphead,*pphead就是头指针的地址	//如果头指针的地址为空,我们就把新开辟的这个空间指针(已经传入值)再赋给头指针,也就是下面的这个if循环	if (*pphead == NULL)	{		*pphead = newNode;	}	else	{		//找尾巴,判断尾巴是不是空地址,这个函数实现的是尾插,我们找到尾巴后,如果尾巴是空地址,我们将插入的newNode赋给尾巴,此时		//实现了尾插,在下面的代码中,我们首先把头指针当成尾巴,从头指针开始依次往后找,如果下一个不是空指针,我们就令		//tail=tail->next,此时指向下一个结点,进入循环继续判断,当找到后,我们再令尾巴=newNode,在上面我们也判断了头指针为空的情况		SListNode* tail = *pphead;		while (tail->next!= NULL)		{			tail = tail -> next;		}		tail->next = newNode;	}}void SListPopBack(SListNode** pphead){	//1、空	//2、一个结点	//3、一个以上	if (*pphead == NULL)	{		return;	}	else if ((*pphead)->next == NULL)	{		free(*pphead);		*pphead = NULL;	}	else	{		SListNode* prev = NULL;		SListNode* tail = *pphead;		while (tail->next != NULL)		{			prev = tail;			tail = tail->next;		}		free(tail);		//tail = NULL;//这个无所谓,因为我们释放后,出了这个作用域,tail和prev都被销毁,没人能拿到,所以不会被再找到		prev->next = NULL;		}}

4、头插头删

//头插头删void SListPushFront(SListNode** pphead, SListDataType x){	SListNode* newnode = BuySListNode(x);	newnode->next = *pphead;	*pphead = newnode;}void SListPopFront(SListNode** pphead){	//1、空	//2、一个结点+3、一个以上		if (*pphead == NULL)	{		return;	}	//(*phead)->next:*和>都是解引用,同一优先级,我们需要给*pphead带括号,(*pphead)->next才是下一个结点		else{		//我们头删也会遇到情况,我们删除第一个的话,第一个里面还存有第二个结点的地址,我们必须在删除前,保存第二个结点的地址		SListNode* next = (*pphead)->next;		free(*pphead);//通过调试我们发现:free前后,*pphead的地址不变,但是*pphead里的值被置为随机值,free不仅仅把这块空间还给操作系统		  //而且还把这块空间存的值和地址都置为随机值		*pphead = next;	}}

 5、单链表查找

//单链表查找SListNode* SListFind(SListNode* phead, SListDataType x){	SListNode* cur = phead;	while (cur)	{		if (cur->data == x)		{			return cur;		}		cur = cur->next;	}	return NULL;}

6、中间插入(在pos后面进行插入)

void SListInserAfter(SListNode** pphead,SListNode* pos, SListDataType x){	assert(pos && pphead);	if (*pphead == pos)	{		SListPushFront(pphead, x);	}	else	{		SListNode* newnode = BuySListNode(x);		SListNode* tmp = *pphead;		while (tmp->next != pos)		{			tmp = tmp->next;		}		tmp->next = pos;		pos->next = newnode;	}	}

 7、中间删除(在pos后面进行删除)

void SListEraseAfter(SListNode* pos){	//删除pos后面的	assert(pos);	if (pos->next)	{		//pos->next=pos->next->next//不推荐		SListNode* next = pos->next;		SListNode* nextnext = next->next;		pos->next = nextnext;		free(next);	}}

8、多带带打印链表和从头到尾打印链表

void SListPrint(SListNode* phead){	SListNode* cur = phead;	while (cur != NULL)	{		printf("%d->", cur->data);		cur = cur->next;	}	printf("NULL/n");}void PrintTailToHead(SListNode* pList){	if (pList == NULL)	{		return;	}	PrintTailToHead(pList->next);	printf("%d->",pList->data);}

9、test.c

#include"SList.h"TestSList1(){	SListNode* pList = NULL;//这个结构体指针指向开辟的空间,头指针指向链表的开头	SListPushBack(&pList, 1);	SListPushBack(&pList, 2);	SListPushBack(&pList, 3);	SListPushBack(&pList, 4);	SListPrint(pList);	SListPopBack(&pList);	SListPopBack(&pList);	SListPopBack(&pList);	SListPopBack(&pList);	SListPopBack(&pList);	SListPrint(pList);	SListPushFront(&pList, 1);	SListPushFront(&pList, 2);	SListPushFront(&pList, 6);	SListPushFront(&pList, 4);	SListPushFront(&pList, 5);	SListPrint(pList);	SListPopFront(&pList);	SListPopFront(&pList);	SListPopFront(&pList);	SListPopFront(&pList);	SListPopFront(&pList);	SListPopFront(&pList);	SListPrint(pList);}TestSList2(){	SListNode* pos1;	SListNode* pList = NULL;//这个结构体指针指向开辟的空间,头指针指向链表的开头	SListPushBack(&pList, 1);	SListPushBack(&pList, 2);	SListPushBack(&pList, 3);	SListPushBack(&pList, 4);	SListPrint(pList);	SListNode* pos = SListFind(pList, 3);	if (pos)	{		pos->data = 30;//这里将cur-data改为pos->data,然后再将pos-data原来的值改为30	}	SListPrint(pList);	pos1 = SListFind(pList, 30);//我们先去找到这个pos1的位置,然后再去插入	SListInserAfter(&pList,pos1,50);//函数传参要对应起来,我们用指针传用指针接收,不能在pos1位置直接写个数字	SListPrint(pList);	SListEraseAfter(pos1);//pList指向第一个结点,pList->next指向第二个结点,那么我们删除的是目标节点后面	SListPrint(pList);	//PrintTailToHead(&pList);}int main(){	TestSList1();	TestSList2();	return 0;	}

 

 

 

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/119292.html

相关文章

  • 数据结构之线性

    摘要:线性表是最基本的数据结构之一,在实际程序中应用非常广泛,它还经常被用作更复杂的数据结构的实现基础。链表之单链表线性表的定义,它是一些元素的序列,维持着元素之间的一种线性关系。 线性表学习笔记,python语言描述-2019-1-14 线性表简介 在程序中,经常需要将一组(通常是同为某个类型的)数据元素作为整体管理和使用,需要创建这种元素组,用变量记录它们,传进传出函数等。一组数据中包含...

    leoperfect 评论0 收藏0
  • 实战PHP数据结构基础之单链

    摘要:常见操作对单链表我们常见的操作有如下语言实现首先我们根据定义实现一个类。单链表是链表这种链式存取数据结构中基础的部分,同样属于链表结构的还有双链表,环形链表和多链表。专题系列基础数据结构专题系列目录地址主要使用语法总结基础的数据结构和算法。 什么是链表? 链表由一个一个的作为节点的对象构成的,每一个节点都有指向下一个节点的指针,最后一个节点的指针域指向空。每个节点可以存储任何数据类型。...

    xumenger 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<