单链表代码


SList.h

#pragma once
//单链表
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>

typedef int SLTDataType;

typedef struct SListNode
{
	SLTDataType data;
    struct SListNode* next;
}SLTNode;

//打印结果
void SLTPrint(SLTNode* phead);

//头插
void SLPushFront(SLTNode** pphead, SLTDataType x);

//尾插
void SLPushTail(SLTNode** pphead, SLTDataType x);

//头删
void SLPopFront(SLTNode** pphead);

//尾删
void SLPopTail(SLTNode** pphead);
// pphead 指向 plist 存放的是 plist 的地址 , *pphead 找到的是 plist 

//查找
SLTNode* SLFind(SLTNode* plist, SLTDataType x);

//不修改,传一级指针,修改时,传二级


//在任意位置(pos)之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);

//在 pos 后插入
void SListInsertAfter(SLTNode* pos, SLTDataType x);


//删除 pos 位置的值
void SListErase(SLTNode** pphead, SLTNode* pos);


//删除 pos 位置后面的值
void SLEraseAfter(SLTNode* pos);


// 单链表的销毁
void SListDestroy(SLTNode** pphead);

SList.c

#include"SList.h"
#define _CRT_SECURE_NO_WARNINGS

//打印结果
void SLTPrint(SLTNode* phead)
{
	//assert(phead);//空链表 --- 可以打印

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

//插入数据时,在堆区开辟空间
SLTNode* Plug_space(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return  NULL;
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
//头插
void SLPushFront(SLTNode** pphead,SLTDataType x)
{
	assert(pphead);
	//pphead 是 plist 的地址
	//当 链表为空时,即 plist 为空, *pphead 为空 ,pphead 不为空
	//若 pphead 为空,在 @1 处,会出现对空指针的解引用

	//assert(*pphead);//不需要,空链表可以插入数据

	/*SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if(newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;*/
	 SLTNode* newnode = Plug_space(x);

	newnode->next = *pphead;
	*pphead = newnode;    //@1
}


//尾插
void SLPushTail(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);

	//assert(*pphead);
	//插入 --- 开辟一块新的空间,在头插过程中也需要开辟一块新的空间,可以将其分装为函数
	SLTNode* newnode = Plug_space(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;//链表中为空,尾插的数据为 newnode
		//要改变的是节点的指针,节点指针的地址(二级指针)
	}
	else
	{
		//找尾节点指针
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		//尾节点,链接新节点
		tail->next = newnode;//要改变的是节点(next成员),节点指针
	}
}

//头删
void SLPopFront(SLTNode** pphead)
{
	assert(pphead);
	//pphead 是 plist 的地址
	//当 链表为空时,即 plist 为空, *pphead 为空 ,pphead 不为空
	//若 pphead 为空,在 @2 处,会出现对空指针的解引用

	//断言,链表是否为空
	assert(*pphead);//链表为空,不能头删

	/*
	//链表中有一个或多个
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;//@2
	}
	else
	{
		SLTNode* del = *pphead;
		*pphead = del->next;//跳过第一个节点
		//*pphead = (*pphead)->next;
		//此处无法识别优先级问题
		free(del);
	}
	*/

	//可以替代上述链表中有一个多个的问题
	SLTNode* del = *pphead;
	//*pphead = del->next;//跳过第一个节点
	*pphead = (*pphead)->next;
	//此处无法识别优先级问题
	free(del);
}

//尾删 1
//void SLPopTail(SLTNode** pphead)
//{
//	//判断链表是否为空,若链表为空,则无法进行尾删,进行断言
//	assert(*pphead);//*pphead 指向 plist 
//
//	//分为链表中有一个/多个
//	if ((*pphead)->next == NULL)
//	{
//		free(*pphead);
//		*pphead = NULL;
//	}
//	//多个
//	else
//	{
//		SLTNode* del = *pphead;
//		//寻找倒数第二个,其 next 的 next 为 NULL,将 倒数第二个的 next 置为 NULL
//		//找尾
//		while(del->next->next)
//		{
//			del = del->next;
//		}
//		free(del->next);
//		del->next = NULL;
//	}
//}


//尾删 2
void SLPopTail(SLTNode** pphead)
{
	assert(pphead);
	//pphead 是 plist 的地址
	//当 链表为空时,即 plist 为空, *pphead 为空 ,pphead 不为空
	//若 pphead 为空,在 @3 处,会出现对空指针的解引用
	
	//判断链表是否为空,若链表为空,则无法进行尾删,进行断言
	assert(*pphead);//*pphead 指向 plist 

	//分为链表中有一个/多个
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;//@3
	}
	//多个
	else
	{
		SLTNode* del = *pphead;
		SLTNode* prve = NULL;

		while (del->next)
		{
			prve = del;
			del = del->next;
		}
		free(del);
		prve->next = NULL;
	}
}

//查找
SLTNode* SLFind(SLTNode* phead, SLTDataType x)
{
	//assert(phead);//此处不需要断言,空链表可以查找

	SLTNode* cur = phead;
	while (cur)//若此处为 cur->next ,会导致最后一个节点进不去,需要在循环结束后手动添加
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;//没找到
}

//在任意位置(pos)之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);

	//若 pos 位于起始位置
	if (*pphead == pos)
	{
		//等价于头插
		SLPushFront(pphead, x);
	}
	// pos 位于其他位置,可以寻找其前一个位置
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		//当 prev-> next 为 pos 时,开辟一个新的空间,进行指针指向的转换,将其连接在一起
		SLTNode* newnode = Plug_space(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}


//在 pos 后插入
void SListInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = Plug_space(x);
	newnode->next = pos->next;
	pos->next = newnode;

	/*
	pos->next = newnode;
	newnode->next = pos->next;// newnode->next = newnode
	*/
}

//删除 pos 位置的值
void SListErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);

	if (*pphead == pos)
	{
		//头删
		SLPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		//当 prev->next == pos
		prev->next = pos->next;
		free(pos);
	}
}


//删除 pos 位置后面的值
void SLEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);//最后一个
	/*pos->next = pos->next->next;
	free(pos->next);*/
	//此处 free(pos->next) 就无法找到 pos->next->next

	SLTNode* next = pos->next;
	pos->next = next->next;
	free(next);// 不影响 pos->next 和 pos->next->next
}

// 单链表的销毁
void SListDestroy(SLTNode** pphead)
{
	//一个节点一个节点的释放
	assert(pphead);

	SLTNode* cur = *pphead;
	while (cur)
	{
		SLTNode* next = cur->next;
		free(cur);
		cur = next;
	}

	*pphead = NULL;
}


//传一级指针,需要在tast.c中将 plist = NULL;

tast.c

#include"SList.h"

#define _CRT_SECURE_NO_WARNINGS

//头插
void TestSList1()
{
	SLTNode* plist = NULL;
	SLPushFront(&plist, 1);
	SLPushFront(&plist, 2);
	SLPushFront(&plist, 3);
	SLPushFront(&plist, 4);
	SLPushFront(&plist, 5);
	SLPushFront(&plist, 6);

	SLTPrint(plist);
}

//尾插
void TestSList2()
{
	SLTNode* plist = NULL;

	SLPushFront(&plist, 6);


	SLPushTail(&plist, 1);
	SLPushTail(&plist, 2);
	SLPushTail(&plist, 3);
	SLPushTail(&plist, 4);
	SLPushTail(&plist, 5);

	SLTPrint(plist);
}

//尾删
void TestSList3()
{
	//头插
	SLTNode* plist = NULL;
	SLPushFront(&plist, 1);
	SLPushFront(&plist, 2);
	SLPushFront(&plist, 3);
	SLPushFront(&plist, 4);
	SLPushFront(&plist, 5);
	SLPushFront(&plist, 6);
	SLTPrint(plist);


	SLPopTail(&plist);
	SLTPrint(plist);

}

//查找
void TestSList4()
{
	//头插
	SLTNode* plist = NULL;
	SLPushFront(&plist, 1);
	SLPushFront(&plist, 2);
	SLPushFront(&plist, 3);
	SLPushFront(&plist, 4);
	SLPushFront(&plist, 5);
	SLPushFront(&plist, 6);
	SLTPrint(plist);

	//查找
	SLTNode* pos = SLFind(plist, 3);
	SLTPrint(plist);

	//修改
	if (pos)
		pos->data = 10;
	SLTPrint(plist);

}

//修改 pos 前 / 后 的值
void TestSList5()
{
	//头插
	SLTNode* plist = NULL;
	SLPushFront(&plist, 1);
	SLPushFront(&plist, 2);
	SLPushFront(&plist, 3);
	SLPushFront(&plist, 4);
	SLPushFront(&plist, 5);
	SLPushFront(&plist, 6);
	SLTPrint(plist);

	//查找
	SLTNode* pos = SLFind(plist, 3);
	SLTPrint(plist);

	//修改 pos 前的值
	if (pos)
	{
		SLInsert(&plist, pos, 10);
	}
	SLTPrint(plist);

	pos = SLFind(plist, 2);
	//修改 pos 后的值
	if (pos)
	{
		SListInsertAfter(pos, 20);
	}
	SLTPrint(plist);

}


//删除 pos 位置的值
void TestSList6()
{
	SLTNode* plist = NULL;

	SLPushTail(&plist, 1);
	SLPushTail(&plist, 2);
	SLPushTail(&plist, 3);
	SLPushTail(&plist, 4);
	SLPushTail(&plist, 5);
	SLTPrint(plist);

	//查找
	SLTNode* pos = SLFind(plist, 3);
	SLTPrint(plist);

	pos = SLFind(plist, 4);
	//删除
	if (pos)
	{
		SListErase(&plist, pos);
	}	
	SLTPrint(plist);
}

//删除 pos 后位置的值
void TestSList7()
{
	SLTNode* plist = NULL;

	SLPushTail(&plist, 1);
	SLPushTail(&plist, 2);
	SLPushTail(&plist, 3);
	SLPushTail(&plist, 4);
	SLPushTail(&plist, 5);
	SLTPrint(plist);

	//查找
	SLTNode* pos = SLFind(plist, 3);
	SLTPrint(plist);

	pos = SLFind(plist, 1);
	//删除
	if (pos)
	{
		SLEraseAfter(pos);
	}
	SLTPrint(plist);
}


int main()
{
	//TestSList1();
	//TestSList2();
	//TestSList3();
	//TestSList4();
	/*TestSList5();*/
	TestSList6();
	/*TestSList7();*/


	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值