数据结构单链表的实现以及相关操作

首先在SListNode.h里面对我们的单链表结点结构体定义,以及相关操作函数进行声明

单链表部分主要相关操作包括单链表的数据的头插、尾插、头删、尾删、

SListNode.h:

#pragma once
typedef int DataType;

typedef struct SListNode
{
	struct SListNode* _next;
	DataType _data;
}SListNode;//结点包括两部分,一个是指向结点类型的指针,一个是用来存放数据的data


SListNode* BuySListNode(DataType x);//创建新的结点
void SListPrint(SListNode* pHead);//打印单链表
void SListDestory(SListNode** ppHead);//摧毁单链表

void SListPushBack(SListNode** ppHead, DataType x);//尾插
void SListPopBack(SListNode** ppHead);//尾删
void SListPushFront(SListNode** ppHead, DataType x);//头插
void SListPopFront(SListNode** ppHead);//头删
SListNode* SListFind(SListNode* pHead, DataType x);//寻找某个结点,返回它的地址
void SListInsest(SListNode** ppHead, SListNode* pos, DataType x);//在pos位置插入结点
void SListErase(SListNode** ppHead, SListNode* pos);//删除pos位置的结点

接着在SListNode.c中对相关的操作函数进行定义,在main函数中进行测试

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"SListNode.h"

SListNode* BuySListNode(DataType x)//创建结点
{
	SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
	if (tmp != NULL)
	{
		tmp->_data = x;
		tmp->_next = NULL;
		return tmp;
	}
	printf("节点创建失败!");
	return tmp;
}

void SListPrint(SListNode* pHead)//打印单链表
{
	if (pHead == NULL)
	{
		printf("该链表为空链表!\n");
	}
	else
	{
		while (pHead)
		{
			printf("%d->", pHead->_data);
			pHead = pHead->_next;
		}
		printf("NULL\n");
	}
}

void SListDestory(SListNode** ppHead)//删除整个单链表
{
	SListNode* tmp;
	if (*ppHead == NULL)
		return;
	else
	{
		while (*ppHead)
		{
			tmp = *ppHead;
			*ppHead = (*ppHead)->_next;
			free(tmp);
			tmp = NULL;
		}
	}
}
void SListPushBack(SListNode** ppHead, DataType x)//从尾部插入数据
{
	SListNode* newNode;
	SListNode* tmp;
	newNode = BuySListNode(x);
	tmp = *ppHead;
	if (NULL == *ppHead)
	{
		*ppHead = newNode;
		(*ppHead)->_next = NULL;
	}
	else
	{
		while (tmp->_next)
		{
			tmp = tmp->_next;
		}
		tmp->_next = newNode;
		newNode->_next = NULL;
	}
}

void SListPopBack(SListNode** ppHead)//从尾部删除数据
{
	//三种情况
	//1.链表为空链表
	//2.链表只有一个结点
	//3.链表有多个节点
	SListNode* tmp;
	tmp = *ppHead;
	if (*ppHead == NULL)
	{
		printf("该链表已经为空表,无需再删除元素!");
	}
	else if ((*ppHead)->_next == NULL)
	{
		free(*ppHead);
		*ppHead = NULL;
	}
	else
	{

		while ((tmp)->_next->_next)
		{
			tmp = tmp->_next;
		}
		free(tmp->_next);
		tmp->_next = NULL;
	}
}

void SListPushFront(SListNode** ppHead, DataType x)//从头部插入数据
{
	SListNode* newNode;
	newNode = BuySListNode(x);
	if (*ppHead == NULL)//链表为空链表
	{
		*ppHead = newNode;
		(*ppHead)->_next = NULL;
	}
	else
	{
		newNode->_next = *ppHead;
		*ppHead = newNode;
	}
}

void SListPopFront(SListNode** ppHead)//从头部删除数据
{
	//三种情况
	//1.链表为空链表
	//2.链表只有一个结点
	//3.链表有多个节点
	SListNode* tmp;
	tmp = *ppHead;
	if (*ppHead == NULL)
	{
		printf("该链表已经为空表,无需再删除元素!");
	}
	else if ((*ppHead)->_next == NULL)
	{
		free(*ppHead);
		*ppHead = NULL;
	}
	else
	{
		*ppHead = (*ppHead)->_next;
		free(tmp);
		tmp = NULL;
	}

}
SListNode* SListFind(SListNode* pHead, DataType x)//找到链表中的某个元素
{
	SListNode* tmp;
	tmp = pHead;
	while (tmp)
	{
		if (tmp->_data == x)
		{
			return tmp;
		}
		tmp = tmp->_next;
	}
	return tmp;
}

void SListInsest(SListNode** ppHead, SListNode* pos, DataType x)//在链表中pos位置插入 x
{
	if (pos == NULL)
	{
		printf("该位置地址为空!无法插入!!\n");
	}
	else
	{
		SListNode* tmp;
		SListNode* newNode;
		newNode = BuySListNode(x);
		tmp = *ppHead;
		if (tmp == pos)
		{
			SListPushFront(ppHead, x);
			return;
		}
		while (tmp)
		{
			if (tmp->_next == pos)
			{
				newNode->_next = tmp->_next;
				tmp->_next = newNode;
				return;
			}
			tmp = tmp->_next;
		}
		printf("该位置不在该顺序表中,插入失败!");
	}
}

void SListErase(SListNode** ppHead, SListNode* pos)//删除链表中pos位置的元素
{
	assert(pos);
	SListNode* tmp;
	SListNode* cur;
	tmp = *ppHead;
	while (tmp->_next == pos)
	{
		tmp = tmp->_next;
	}
	cur = tmp->_next;
	tmp->_next = tmp->_next->_next;
	free(cur);
	cur = NULL;
}

int main()
{
	SListNode* SList;
	SList = BuySListNode(1);
	SListPushBack(&SList,2);
	SListPushBack(&SList, 3);
	SListPushBack(&SList, 4);
	SListPushBack(&SList, 5);
	SListPrint(SList);
	SListPopBack(&SList);
	SListPushFront(&SList, 8);
	SListPrint(SList);
	SListInsest(&SList,SListFind(SList, 2), 9);
	SListPopFront(&SList);
	SListPrint(SList);
	SListErase(&SList, SListFind(SList, 2));
	SListPrint(SList);
	SListDestory(&SList);
	SListPrint(SList);
	system("pause");
	return 0;
}

在对单链表进行摧毁删除时应该注意每一个结点都必须对它的内存进行释放,因为链表的这些结点每次插入新结点的时候都是在内存空间中用malloc进行申请,这些空间是不连续的。

跟顺序表的连续内存空间相比,单链表释放时要逐个释放,而不是只释放头结点然后将头指针置空,这块需要特别注意不能释放头结点后直接把指针置空,避免因为指针置空而找不到后续结点,导致内存泄漏 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值