栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > C/C++/C#

c语言单向链表

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c语言单向链表

c语言实现简单的单向链表


文章目录
  • 一、单向链表是什么?
  • 二、功能代码实现
  • 三、代码实现单向链表
  • 四、总结
一、单向链表是什么?

单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;链表是使用指针进行构造的列表;又称为结点列表,因为链表是由一个个结点组装起来的;其中每个结点都有指针成员变量指向列表中的下一个结点;(下图来自百度)

 

二、功能代码实现 1.包含头文件
#include
#include
#include
#include
2.结构体(结点)
typedef int SLTDataType;//宏定义成员为整形
typedef struct SListNode
{
	SLTDataType data;//资料
	struct SListNode* next;//连接下一个节点的链子
}SLTNode;
3.定义
SLTNode* BuyNewNode(SLTDataType X);//创建新节点
void SListPrint(SLTNode* phead);//打印
void SListDestory(SLTNode**phead);//销毁
void SListPushFront(SLTNode** pphead, SLTDataType X);//头插
void SListPushBack(SLTNode** pphead, SLTDataType X);//尾插
void SListPopFront(SLTNode** pphead);//头删
void SListPopBack(SLTNode** pphead);//尾删
SLTNode* SListFind(SLTNode* pphead, SLTDataType X);//查询
void SListInsert(SLTNode** pphead,SLTNode*pos, SLTDataType X);//插入-在pos之前插入
void SListInsert( SLTNode* pos, SLTDataType X);//插入-在pos之后插入
4.各类功能实现
SLTNode* BuyNewNode(SLTDataType X);//创建新节点-结构体指针类型函数-传值
SLTNode* BuyNewNode(SLTDataType X)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//先开辟一块空间给新节点
	if (newnode == NULL)//如果新节点为空-即开辟失败则报错
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = X;//把X的值赋给新节点的data
	newnode->next = NULL;//把链子设为空指针
	return newnode;//把节点传回去
}

void SListPrint(SLTNode* phead);//打印

void SListPrint(SLTNode* phead)
{
	SListNode* cur = phead;//新建一个结构体指针为表头
	while (cur != NULL)//如果指针指向的内容不为空则打印内容
	{
		printf("%d->", cur->data);
		cur = cur->next;
}
	printf("NULLn");//为空则打印空指针
}

void SListDestory(SLTNode**phead);//销毁

void SListDestory(SLTNode** pphead)
{
	assert(pphead);//指向节点的指针不能为空
	SLTNode* cur = *pphead;//新建一个临时节点为链表头
	while (cur)//临时节点不为空时
	{
		SLTNode* next = cur->next;//链表下一个节点为临时节点的的下一个节点
		free(cur);//释放当前节点
		cur = next;//当前节点为下一个节点
	}
	*pphead = NULL;//最后释放完链表后置指针为空
}
void SListPushFront(SLTNode** pphead, SLTDataType X);//头插
void SListPushFront(SLTNode** pphead, SLTDataType X)//头插-链表吧不为空,要改变的是SList-用地址
{
	assert(pphead);
	SLTNode* newnode = BuyNewNode(X);//新建其含有对应内容的新节点
	newnode->next = *pphead;//新节点的下一个节点为表头
	*pphead = newnode;//新节点充当表头
}
void SListPopFront(SLTNode** pphead);//头删
void SListPopFront(SLTNode** pphead)//头删
{
	assert(pphead);
//	if (*pphead == NULL)//温柔检查
//	{
//		return;
//
//}
	assert(*pphead != NULL);//暴力检查
	
	SLTNode* del = *pphead;//建立新节点为表头
	*pphead = (*pphead)->next;//表头的下一个节点为表头
	free(del);//释放表头
	del = NULL;//新节点指针置为空
}
void SListPushBack(SLTNode** pphead, SLTDataType X);//尾插
void SListPushBack(SLTNode** pphead, SLTDataType X)//尾插-链表不为空,要改变的是SList 的成员-用结构体指针即可
{
	assert(pphead);
	SLTNode* newnode = BuyNewNode(X);//新建
	if (*pphead == NULL)//一种情况为表头为空-即链表只有一个空节点
	{
		*pphead = newnode;
	}
	else//另一种情况要找尾巴
	{
		//找尾
		SLTNode* tail = *pphead;//建立新节点为表头,依次找到表尾
		while(tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;//表尾替换为含有对应内容的新节点
	}
}

void SListPopBack(SLTNode** pphead);//尾删

A-单指针法

void SListPopBack(SLTNode** pphead)//尾删
{
	//	if (*pphead == NULL)//温柔检查
//	{
//		return;
//
//}
	assert(*pphead != NULL);//暴力检查
	assert(pphead);
	//对应链表只有一个节点-直接释放
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else//对应链表有多个节点
	{
		//找尾
		SLTNode* tail = *pphead;//新建节点为表头-开始找尾

		if (tail->next->next != NULL)//表尾为空指针-即要删除表尾前一个节点
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}



B-双指针(快慢指针法)

void SListPopBack(SLTNode** pphead)//尾删
{
	assert(pphead);
		//找尾
		SLTNode* tail = *pphead;
		SLTNode* open = NULL;
		while (tail->next != NULL)
		{
			open = tail;
			tail = tail->next;
		}
		open->next = NULL;
		free(tail->next);
		tail = NULL;
	
}

SLTNode* SListFind(SLTNode* pphead, SLTDataType X);//查询

SLTNode* SListFind(SLTNode* phead, SLTDataType X)
{
	SLTNode* cur = phead;//临时节点为表头
	while (cur)//临时节点不为空-还没遍历完链表
	{
		if (cur->data == X)//找到就返回临时节点
		{
			return cur;
		}
			cur = cur->next;
	}
	return NULL;//没找到返回空指针
	
}

void SListInsert(SLTNode** pphead,SLTNode*pos, SLTDataType X);//插入-在pos之前插入

void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType X)//插入-在pos之前插入
{
	assert(pphead);
	assert(pos);
	if (pos == *pphead)//pos为表头直接用头插
	{
		SListPushFront(pphead,X);
	}
	else {
		SListNode* pre = *pphead;
		while (pre->next != pos)
		{
			pre = pre->next;
			assert(pre);//找到NULL还没找到pos说明pos传错了
		}
		SListNode* newnode = BuyNewNode(X);//串连起来
		pre->next = newnode;
		newnode->next = pos;
	}
}

void SListInsert( SLTNode* pos, SLTDataType X);//插入-在pos之后插入

void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType X)//插入-在pos之后插入
{
	assert(pos);
	SListNode* newnode = BuyNewNode(X);
	newnode->next = pos->next;
	pos->next = newnode;
}

三、代码实现单向链表

SList.h

#include
#include
#include
#include
typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;
SLTNode* BuyNewNode(SLTDataType X);//创建新节点
void SListPrint(SLTNode* phead);//打印
void SListDestory(SLTNode**phead);//销毁
void SListPushFront(SLTNode** pphead, SLTDataType X);//头插
void SListPushBack(SLTNode** pphead, SLTDataType X);//尾插
void SListPopFront(SLTNode** pphead);//头删
void SListPopBack(SLTNode** pphead);//尾删
SLTNode* SListFind(SLTNode* pphead, SLTDataType X);//查询
void SListInsert(SLTNode** pphead,SLTNode*pos, SLTDataType X);//插入-在pos之前插入
void SListInsert( SLTNode* pos, SLTDataType X);//插入-在pos之后插入
void SListEarse(SLTNode** pphead,SLTNode*pos);//删除-删除pos

SList.cpp

//顺序表的缺点
//1.中间或中部的插入和删除,时间复杂度为o(n)
//2.增容需要申请空间,拷贝数据,释放旧空间,会有消耗
//3.扩容一般以2倍的增长,易造成空间浪费

//链表
//无头单向非循环单链表:结构简单,一般不会单独用来存数据,实际上更多作为其他数据结构的子结构,如哈希表,图的邻接表
#include"SList.h"

void SListPrint(SLTNode* phead)
{
	SListNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
}
	printf("NULLn");
}
SLTNode* BuyNewNode(SLTDataType X)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = X;
	newnode->next = NULL;
	return newnode;
}
void SListPushFront(SLTNode** pphead, SLTDataType X)//头插-链表吧不为空,要改变的是SList-用地址
{
	assert(pphead);
	SLTNode* newnode = BuyNewNode(X);
	newnode->next = *pphead;
	*pphead = newnode;
}

void SListPushBack(SLTNode** pphead, SLTDataType X)//尾插-链表不为空,要改变的是SList 的成员-用结构体指针即可
{
	assert(pphead);
	SLTNode* newnode = BuyNewNode(X);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		//找尾
		SLTNode* tail = *pphead;
		while(tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}
void SListPopFront(SLTNode** pphead)//头删
{
	assert(pphead);
//	if (*pphead == NULL)//温柔检查
//	{
//		return;
//
//}
	assert(*pphead != NULL);//暴力检查
	
	SLTNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
	del = NULL;
}
//void SListPopBack(SLTNode** pphead)//尾删
//{
//	assert(pphead);
//		//找尾
//		SLTNode* tail = *pphead;
//		SLTNode* open = NULL;
//		while (tail->next != NULL)
//		{
//			open = tail;
//			tail = tail->next;
//		}
//		open->next = NULL;
//		free(tail->next);
//		tail = NULL;
//	
//}
void SListPopBack(SLTNode** pphead)//尾删
{
	//	if (*pphead == NULL)//温柔检查
//	{
//		return;
//
//}
	assert(*pphead != NULL);//暴力检查
	assert(pphead);
	//一个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else//多个节点
	{
		//找尾
		SLTNode* tail = *pphead;

		if (tail->next->next != NULL)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

void SListDestory(SLTNode** pphead)
{
	assert(pphead);
	SLTNode* cur = *pphead;
	while (cur)
	{
		SLTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}
SLTNode* SListFind(SLTNode* phead, SLTDataType X)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == X)
		{
			return cur;
		}
			cur = cur->next;
	}
	return NULL;
	
}
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType X)//插入-在pos之前插入
{
	assert(pphead);
	assert(pos);//在pos之前插入
	if (pos == *pphead)
	{
		SListPushFront(pphead,X);
	}
	else {
		SListNode* pre = *pphead;
		while (pre->next != pos)
		{
			pre = pre->next;
			assert(pre);//找到NULL还没找到pos说明pos传错了
		}
		SListNode* newnode = BuyNewNode(X);
		pre->next = newnode;
		newnode->next = pos;
	}
}
void SListEarse(SLTNode** pphead, SLTNode* pos)//删除-删除pos
{

}
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType X)//插入-在pos之后插入
{
	assert(pos);
	SListNode* newnode = BuyNewNode(X);
	newnode->next = pos->next;
	pos->next = newnode;
}

test.cpp

#include"SList.h"
void TestSList1()
{
	SLTNode* plist = NULL;
	SListPushFront(&plist, 1);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 4);
	SListPrint(plist);
	SLTNode* pos = SListFind(plist, 4);
	if (pos)
	{
		pos->data *= 2;
		printf("找到了n");
	}
	else
	{
		printf("没找到n");
	}
	SListPrint(plist);
	SListInsert(&plist,pos, 20);
	SListPrint(plist);
	SListDestory(&plist);
	SListPrint(plist);
}
int main()
{
	TestSList1();
	return 0;
}

以上只实现了部分功能,具体可以参考上功能代码实现,或者进到我的链接看噢

https://github.com/divertlee/opening.git


四、总结

本人纯新手昂,有啥问题评论区cue我噢,谢谢观看!!!

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1037957.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号