单链表基本功能的实现(C语言)

Posted Enthusiastic_boy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单链表基本功能的实现(C语言)相关的知识,希望对你有一定的参考价值。

链表:每个节点包含两部分,一部分存放数据变量的data,另一部分是指向下一节点的next指针。

以下来实现不带头节点的单链表。每一个节点是结构体类型的,如下所示:

typedef struct SListNode
	DateType data;//数据域
	struct SListNode* next;//指针域
SListNode;

单链表最基本的功能有:头插,头删,尾插,尾删.......等,在每次头插或者尾插时都需要申请一个新的节点,所以把单独申请节点封装成一个函数,将申请到的节点的地址返回即可,代码如下:

SListNode * BuySListNode(DateType x)//在堆上动态申请一个节点,并返回节点首的地址
	SListNode *cur =(SListNode *) malloc(sizeof(SListNode));//申请大小为sizeof(SListNode)的空间
	if (cur == NULL)//申请失败,直接退出程序
		perror("malloc");
		exit(0);
	
	cur->data = x;//修改申请的节点的data的值
	cur->next = NULL;//将新申请的节点的next置为空
	return cur;

首先会定义一个结构体指针,让它先指向空,然后通过调用不同的函数来实现不同的功能。

SListNode *plist=NULL;

1.头插:

void SListPushFront(SListNode ** plist, DateType x)//头插
	assert(plist);//判断指针的合法性
	SListNode *cur = *plist;//赋值后,cur此时相当于头指针
	*plist = BuySListNode(x);//改变头指针的指向,使其指向新申请的节点
	(*plist)->next = cur;//让新申请的节点的next指向原来的链表头

为什么要使用二级指针?因为在这里的每一次头插都需要改变指针plist的指向,而且头插的这个函数没有返回值,所以只有对函数中的二级指针解引用才能拿到真正的函数头指针,从而对它进行操作,改变它的指向。如果不想使用二级指针,那么函数必须要有返回值,而且返回值为:SListNode *类型。

2.尾插:

void SListPushBack(SListNode ** plist, DateType x)//尾插
	if (*plist == NULL)//链表中没有节点,此时直接插入
		*plist = BuySListNode(x);
	
	else
		SListNode *cur = *plist;
		while (cur->next)//cur的next为空,说明找到了最后一个节点,为尾插做准备
			cur = cur->next;
		
		cur->next = BuySListNode(x);//插入节点
	

尾插也需要使用二级指针,因为如果链表中没有节点那么此时还是需要改变定义出来的头指针的指向,这是一种特殊情况。如果要插入的链表中的节点个数>=1,那么此时可以不使用二级指针,因为一定可以找到最后一个节点的next域。

3.头删:每次需要改变头指针的指向,所以必须使用二级指针。

4.尾删:当链表只有一个节点的时候,这也属于一种特殊情况,因为此时要让链表的头指针指向空,所以要使用二级指针。如果要删除的链表中的节点个数>1,此时可以不使用二级指针,因为不需要改变头指针的指向。

搞清楚了二级指针在什么情况下使用,那么写出单链表的增、删、改、查就容易了,以下是完整代码和测试用例,使用多文件:

1.SListNode.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include <assert.h>
typedef int DateType;
typedef struct SListNode
	DateType data;
	struct SListNode* next;
SListNode;
extern SListNode * BuySListNode(DateType x);
extern void SListPushBack(SListNode ** plist, DateType x);
extern void SListPushFront(SListNode ** plist, DateType x);
extern void SListPopFront(SListNode **plist);
extern void SListPopBack(SListNode **plist);  
extern void SListInsertAfter(SListNode* pos, DateType x);
extern void SListPrint(SListNode *plist);

2.SListNode.c

#include "SListNode.h"
SListNode * BuySListNode(DateType x)//在堆上动态申请一个节点,并返回节点首的地址
	SListNode *cur =(SListNode *) malloc(sizeof(SListNode));//申请大小为sizeof(SListNode)的空间
	if (cur == NULL)//申请失败,直接退出程序
		perror("malloc");
		exit(0);
	
	cur->data = x;//修改申请的节点的data的值
	cur->next = NULL;//将新申请的节点的next置为空
	return cur;

void SListPushFront(SListNode ** plist, DateType x)//头插
	assert(plist);//判断指针的合法性
	SListNode *cur = *plist;//赋值后,cur此时相当于头指针
	*plist = BuySListNode(x);//改变头指针的指向,使其指向新申请的节点
	(*plist)->next = cur;//让新申请的节点的next指向原来的链表头

void SListPopFront(SListNode **plist)//头删
	if (*plist == NULL)//链表中没有节点,不用删除
		return;
	
	else
		SListNode *cur = *plist;//赋值后,cur此时相当于头指针
		*plist = (*plist)->next;//让头指针指向原来链表中的第二个节点
		free(cur);//释放要删除的节点所占用的空间
	

void SListPushBack(SListNode ** plist, DateType x)//尾插
    assert(plist);
	if (*plist == NULL)//链表中没有节点,此时直接插入
		*plist = BuySListNode(x);
	
	else
		SListNode *cur = *plist;
		while (cur->next)//cur的next为空,说明找到了最后一个节点,为尾插做准备
			cur = cur->next;
		
		cur->next = BuySListNode(x);//插入节点
	

void SListPopBack(SListNode **plist)//尾删
	if (*plist == NULL)//没有节点,直接返回
		return;
	
	else if (((*plist)->next)==NULL)//只有一个节点,此时可以直接删除
		free(*plist);
		*plist = NULL;
	
	else
		SListNode *cur = *plist;//赋值后,cur此时相当于头指针
		SListNode *prev = cur;//赋值后,prev此时相当于头指针
		while (cur->next)//寻找最后一个节点,cur指向最后一个节点,而prev指向最后一个节点的前一个节点
			prev = cur;
			cur = cur->next;
		
		prev->next = NULL;//把倒数第二个节点的next置空
		free(cur);//释放最后一个节点所占用的空间
	

void SListPrint(SListNode *plist)//打印
	if (plist == NULL)
		printf("没有元素\\n");
		return;
	
	SListNode * cur = plist;
	while(cur)//遍历单链表,直到cur为空
		printf("->%d", cur->data);
		cur = cur->next;
	 
	printf("\\n");

SListNode* SListFind(SListNode* plist, DateType x)//查找
	if (plist == NULL)
		printf("没有元素\\n");
		return NULL;
	
	SListNode *cur = plist;
	while (cur!=NULL)
		if (cur->data == x)
			printf("找到了\\n");
			return cur;
		
		cur = cur->next;
	
	return NULL;

void SListInsertAfter(SListNode* pos, DateType x)//在pos位置之后插入
	if (pos == NULL)
		return;
	
	SListNode *cur = BuySListNode(x);
	cur->next = pos->next;
	pos->next = cur;
	/*SListNode *cur = pos->next;
	pos->next = BuySListNode(x);
	pos->next->next = cur;*/


void SListEraseAfter(SListNode* pos)//删除pos位置之后的节点
	if (pos == NULL||(pos->next)==NULL)
		return;
	
	SListNode *cur = pos->next;
	pos->next = cur->next;
	free(cur);

3.main.c

#include "SListNode.h"
int main()
	SListNode *plist=NULL;
	SListPushFront(&plist, 7);
	SListPushFront(&plist, 9);
	SListPrint(plist);
	SListPushBack(&plist, 5);
	SListPushBack(&plist, 4);
	SListPrint(plist);
	SListPopFront(&plist);
	SListPrint(plist);
	SListPopBack(&plist);
	SListPrint(plist);
	SListInsertAfter(plist,85);
	SListPrint(plist);
	system("pause");
	return 0;

运行程序后,结果如下:

以上是关于单链表基本功能的实现(C语言)的主要内容,如果未能解决你的问题,请参考以下文章

单链表的基本操作操作,类C语言

C语言实现单链表(带头结点)的基本操作

数据结构单链表的介绍和基本操作(C语言实现)保姆级别详细教学

数据结构代码(用C语言) 单链表的插入和删除

数据结构-单链表基本操作(c语言实现)

单链表的基本操作实现