数据结构——单链表讲解及实现

单链表介绍,单链表讲解以及实现

大家好,还是我这位老实人,今天来讲解和实现一下单链表。但是我们要先说一下链表,链表,是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。那么,这种链式结构在逻辑上是连续的,但是在物理上不一定连续。 下面进入正题环节
今天的自拍也很美

单链表的讲解

回到单链表,顾名思义,便是单方向的链表,有单链表肯定也有双链表,这个下节再议。单链表结构简单,一般不会用来存储数据,但是因为我是老实初学者,所以还是要脚踏实地,踏踏实实的写出来,下图便是单链表的示意图,非常的简单易懂。
这也太简单了

单链表的实现

接口声明

进入正题,想要实现单链表,进行接口的声明不能少,所以,下面直接介绍单链表的接口:

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


typedef int SLTDateType;
typedef struct SListNode {
	SLTDateType data;
	struct SListNode* next;
}SListNode,SN;

SN* BuySListNode(SLTDateType x);
void SListPrint(SN* plist);

void SListPushBack(SN** pplist, SLTDateType x);
void SListPushFront(SN** pplist, SLTDateType x);
void SListPopBack(SN** pplist);
void SListPopFront(SN** pplist);

SN* SListFind(SN* plist, SLTDateType x);

//分析思考为什么不在pos位置前插入
//答:因为太麻烦了,要是在前面插入的话根本没有前面的地址,只能遍历出来再搞
void SListInsertAfter(SN* pos, SLTDateType x);

//分析思考为什么不删除pos位置
//答:和上面的一样,因为没有上面的地址
void SListEraseAfter(SN* pos);

void SListDestroy(SListNode** pphead);

相信大家可能会有疑问,但是有的疑问后续会讲,有的疑问已经放在代码块里了。请大家自行翻阅

接口实现

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

当然,先来的还是最简单的打印单链表

SN* BuySListNode(SLTDateType x) {
	SN* SListNode = (SN*)malloc(sizeof(SN));
	if (SListNode == NULL) {
		printf("buy slistnode fail\n");
		exit(-1);
	}
	else {
		SListNode->data = x;
		SListNode->next = NULL;
	}
	return SListNode;
}

顾名思义,买一个节点,便是创造出一个新的节点,使用开辟内存的malloc创造,并将新节点的值设置为要设置的值,将新节点的下一个链接的地址置为NULL

void SListPushBack(SN** pplist, SLTDateType x) {
	assert(pplist);
	SN* newnode = BuySListNode(x);
	if (*pplist == NULL) {
		*pplist = newnode;
	}
	else {
		SN* tail = *pplist;
		while (tail->next) {
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

void SListPushFront(SN** pplist, SLTDateType x) {
	assert(pplist);
	SN* newnode = BuySListNode(x);
	/*if (*pplist) {
		newnode->next = *pplist;
		*pplist = newnode;
	}
	else {
		*pplist = newnode;
	}*/
	//没必要上面的,下面的确实更方便,即使链表为空也是没问题
	newnode->next = *pplist;
	*pplist = newnode;
}


void SListPopBack(SN** pplist) {
	assert(pplist);
	if (*pplist == NULL) {
		return;
	}
	else if((*pplist)->next == NULL){
		free(*pplist);
		*pplist = NULL;
	}
	else {
		SN* tail = *pplist;
		while (tail->next->next) {
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

void SListPopFront(SN** pplist) {
	assert(pplist);
	if (*pplist == NULL) {
		return;
	}
	else {
		SN* newhead = (*pplist)->next;
		free(*pplist);
		*pplist = newhead;
	}
}

这便是经典的push和pop四组函数了,但是根据上述代码的分析,pushfront和popfront都是非常简单的操作,所以单链表尽量进行pushfront和popfront,还是因为单链表过于简单所以其函数都比较极端,方便的很方便,麻烦的很麻烦。
当然,这里面最重要的还是这四个函数的输入参数都是SN指针的指针,也就是双指针,因为如果pushfront和pushback的情况是单链表中没有元素,那么就需要将开头元素的NULL改成需要push的元素的地址,但是如果传的SN的指针的话,那么将无法修改,因为在函数里这只是形参的改变,实参不会改变,就类似于int a后,使用一个参数为int的函数changeint(int)是无法对a进行修改的,我们需要将changeint的输入参数变为int的地址或者int的指针才可以对a的值进行修改;而popback和popfront也是同理,这里不再过多赘述。

SN* SListFind(SN* plist, SLTDateType x) {
	/*if (plist) {
		printf("no data\n");
	}
	else {
		SN* cur = plist;
		while (cur->next) {
			if (cur->data == x) {
				return cur;
			}
			cur = cur->next;
		}
		printf("can not find\n");
		return NULL;
	}*/
	//下面的更方便一点,我这个考虑的过多了

	SListNode* cur = plist;
	while (cur != NULL)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

void SListInsertAfter(SN* pos, SLTDateType x) {
	assert(pos);
	SN* newnode = BuySListNode(x);
	SN* next = pos->next;
	pos->next = newnode;
	newnode->next = next;
}


void SListEraseAfter(SN* pos) {
	assert(pos);
	if (pos->next) {
		SN* cur = pos->next;
		pos->next = pos->next->next;
		free(cur);
		cur = NULL;
	}
}


void SListDestroy(SListNode** pphead) {
	assert(pphead);
	SN* cur = *pphead;
	while (cur) {
		SN* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

好的,最后四组函数没有过多的含金量,相信大家在理解前面的代码后,看到这四个函数会发现其实很简单,也只是进行最基础的一个应用。

单链表的总结

单链表作为数据结构的基础,对于新手来说还是非常友好的,也希望我能一直坚持下去,努力完成学业,也希望看到这里的观众事业顺利,心想事成,下次再见

泪目

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值