链表Day17 20240719

一、链表相关练习

1.链表的相关操作

1>seqlist.h

#ifndef LINKLIST_H
#define LINKLIST_H
#include <myhead.h>

//数据类型重定义
typedef int datatype;

//定义节点类型
typedef struct Node 
{
	union
	{
		int len;			//头结点数据域
		datatype data;		//普通节点数据域
	};
	struct Node *next;				//指针域
}Node, *NodePtr;

//创建链表
NodePtr LinklistCreat();

//申请节点封装数据
NodePtr ApplyNode(datatype e);

//链表判空
int ListEmpty(NodePtr L);

//头插数据
int ListInsertHead(NodePtr L, datatype e);

//链表遍历
int ListShow(NodePtr L);

//通过位置查找节点
NodePtr ListSearchPos(NodePtr L, int pos);

//任意位置插入数据
int ListInsertPos(NodePtr L, int pos, datatype e);

//头删数据
int ListDeleteHead(NodePtr L);

//任意位置删除数据
int ListDeletePos(NodePtr L, int pos);

//按值查找返回位置
int ListSearchValue(NodePtr L, datatype e);

//按位置修改
int ListUpdatePos(NodePtr L, int pos, datatype e);

//按值修改
int ListUpdateValue(NodePtr L, datatype old_e, datatype new_e);

//链表反转
int ListReverse(NodePtr L);

//链表排序
int ListSort(NodePtr L);

//链表反转(递归)
NodePtr ListReverseRecursion(NodePtr L);

//链表去重
int ListDeduplication(NodePtr L);

//链表连接(不去重)
NodePtr ListCatSort(NodePtr L1, NodePtr L2);

//链表释放
int ListFree(NodePtr L);

#endif

2>seqlist.c

#include "linklist.h"

//创建链表
NodePtr LinklistCreat()
{
	//创建头结点
	NodePtr L =(NodePtr)malloc(sizeof(Node));

	//判断逻辑
	if(L == NULL)
	{
		printf("创建失败\n\n");
		return NULL;
	}

	//创建成功,初始长度置零
	L->next = NULL;			//防止野指针
	L->len = 0;

	printf("创建成功\n\n");
	return L;
}

//申请节点封装数据
NodePtr ApplyNode(datatype e)
{	
	//创建节点容器
	NodePtr P =(NodePtr)malloc(sizeof(Node));

	//判断逻辑
	if(P == NULL)
	{
		printf("封装失败\n\n");
		return NULL;
	}

	//容器创建成功,开始封装
	P->data = e;		//数据封装
	P->next = NULL; 	//指针域,防止野指针

	return P;
}

//链表判空
int ListEmpty(NodePtr L)
{
	return L->next == 0;
}

//头插数据
int ListInsertHead(NodePtr L, datatype e)
{
	//判断逻辑
	if(L == NULL)
	{
		printf("头插失败\n\n");
		return -1;
	}
	
	//数据封装
	NodePtr P = ApplyNode(e);
	if(P==NULL)
	{
		printf("头插失败\n\n");
		return -1;
	}
	
	//头插逻辑
	P->next = L->next;
	L->next = P;

	//表长度变化
	L->len++;

	//printf("头插成功\n\n");
	return 0;
}

//链表遍历
int ListShow(NodePtr L)
{
	//判断逻辑
	if(L==NULL || ListEmpty(L))
	{
		printf("遍历失败\n\n");
		return -1;
	}

	//遍历逻辑
	//定义第一个节点,从第一个开始向后遍历
	printf("链表中的元素分别是:");
	NodePtr Q = L->next;		
	while(Q != NULL)
	{
		printf("%d\t", Q->data);
		//打印完成,指向下一节点
		Q = Q->next;			
	}

	printf("\n\n");
	return 0;
}

//通过位置查找节点
NodePtr ListSearchPos(NodePtr L, int pos)
{
	//判断逻辑
	if(L==NULL || ListEmpty(L) || pos<1 || pos>L->len)
	{
		printf("查找失败\n\n");
		return NULL;
	}

	//查找逻辑,查找pos位节点前区所指向位置
	NodePtr Q = L;
	//从第一个遍历到第pos-1位
	for(int i=0; i<pos; i++)
	{
		Q = Q->next;
	}
	
	//printf("查找完成\n\n");
	return Q;
}

//任意位置插入数据
int ListInsertPos(NodePtr L, int pos, datatype e)
{
	//判断逻辑
	if(L==NULL ||ListEmpty(L) || pos<1 || pos>L->len+1)
	{
		printf("插入失败\n\n");
		return -1;
	}

	//封装数据
	NodePtr P = ApplyNode(e);
	if(P == NULL)
	{
		return -1;
	}

	//位置查找
	NodePtr Q = ListSearchPos(L, pos-1);

	//插入逻辑
	P->next = Q->next;
	Q->next = P;
	L->len++;
	
	printf("插入成功\n\n");
	return 0;
}

//头删数据
int ListDeleteHead(NodePtr L)
{
	//判断逻辑
	if(L==NULL || ListEmpty(L))
	{
		printf("头删失败\n\n");
		return -1;
	}

	//头删逻辑
	NodePtr Q = L->next;
	L->next = Q->next;
	free(Q);
	Q = NULL;		//防止野指针

	L->len--;
	//printf("头删成功\n\n");
	return 0;
}

//任意位置删除数据
int ListDeletePos(NodePtr L, int pos)
{
	//判断逻辑
	if(L==NULL || ListEmpty(L) || pos<1 || pos>L->len)
	{
		printf("删除失败\n\n");
		return -1;
	}

	//前驱位置查找
	NodePtr P = ListSearchPos(L, pos-1);

	//删除逻辑
	NodePtr Q = P->next;
	P->next = P->next->next;
	free(Q);
	Q = NULL;
	
	L->len--;
	printf("删除成功\n\n");
	return 0;
} 

//按值查找返回位置
int ListSearchValue(NodePtr L, datatype e)
{
	//判断逻辑
	if(L==NULL || ListEmpty(L))
	{
		printf("查找失败\n\n");
		return 0;
	}

	//判断逻辑,遍历链表
	NodePtr P = L->next;
	for(int i=1; i<=L->len; i++)
	{
		if(e == P->data)
		{
			return i;
		}
		P = P->next;
	}

	printf("查无此值\n\n");
	return -1;
}

//按位置修改
int ListUpdatePos(NodePtr L, int pos, datatype e)
{
	//判断逻辑
	if(L==0 || ListEmpty(L) || pos<1 || pos>L->len)
	{
		printf("修改失败\n\n");
		return -1;
	}

	//位置查找
	NodePtr P = ListSearchPos(L, pos);

	//修改逻辑
	P->data = e;

	printf("修改成功\n\n");
	return 0;
}

//按值修改
int ListUpdateValue(NodePtr L, datatype old_e, datatype new_e)
{
	//判断逻辑
	if(L==NULL || ListEmpty(L))
	{
		printf("修改失败\n\n");
		return 0;
	}

	//查找旧值位置
	int res = ListSearchValue(L, old_e);
	if(res == -1)
	{
		printf("修改失败\n\n");
		return -1;
	}

	//位置查找
	ListUpdatePos(L, res, new_e);

	printf("修改成功\n\n");
	return 0;
}

//链表反转
int ListReverse(NodePtr L)
{
	//判断逻辑
	if(L==NULL || L->len<2)
	{
		printf("反转失败\n\n");
		return -1;
	}
	
	//反转逻辑
	NodePtr H = L->next;
	L->next = NULL;
	NodePtr P = NULL;
	while(H != NULL)
	{
		P = H;
		H = H->next;
		P->next = L->next;
		L->next = P;
		
	}

	printf("反转成功\n\n");
	return 0;
}

//链表排序
int ListSort(NodePtr L)
{
	if(L==NULL || L->len<2)
	{
		printf("排序失败\n\n");
	}

	//排序逻辑
	//创建交换节点
	NodePtr P = L->next;
	while(P)
	{
		//遍历链表
		NodePtr Q = P->next;
		while(Q)
		{
			if(P->data > Q->data)
			{
				datatype temp = P->data;
				P->data = Q->data;
				Q->data = temp;
			}
			Q = Q->next;
		}
		P = P->next; 
	}
	printf("排序完成\n\n");
	return 0;
}

//链表反转(递归)
NodePtr ListReverseRecursion(NodePtr L)
{
	//递归出口
	if(L==NULL || L->next==NULL)
	{
		printf("反转成功\n\n");
		return L;
	}
	
	//反转逻辑
	//如果L不是最后一个节点
	NodePtr H = ListReverseRecursion(L->next);  //先找到最后一个节点
	//让下一个节点的指针域指向自己
	L->next->next = L; 
	L->next = NULL;		//当前节点指针域置空
	
	return H;
}

//链表去重
int ListDeduplication(NodePtr L)
{
	if(L==NULL || ListEmpty(L))
	{
		printf("去重失败\n\n");
		return -1;
	}

	//去重逻辑
	NodePtr H = L->next;	//定义第一个节点
	NodePtr P = NULL;		//定义重复节点标记
	while(H)
	{
		P = H;
		while(P->next)
		{
			if(H->data == P->next->data)
			{	
				//P直接指向下一节点
				P->next = P->next->next;
				
			}
			else
			{
				//向下一节点遍历
				P = P->next;
			}
		}
		H = H->next;
	}

	printf("去重成功\n\n");
	return 0;
}

//链表释放
int ListFree(NodePtr L)
{
	//判断逻辑
	if(L==NULL)
	{
		printf("释放失败\n\n");
		return -1;
	}
	
	//将所有节点释放
	while(!ListEmpty(L))
	{
		//头删
		ListDeleteHead(L);
	}

	free(L);
	L = NULL;		//防止野指针

	printf("释放成功\n\n");
	return 0;
}

3>main.c

#include "linklist.h"

int main(int argc, const char *argv[])
{	
	//调用函数创建链表
	NodePtr L = LinklistCreat();
	if(L == NULL)
	{
		printf("创建失败\n\n");
		return -1;
	}
	
	//调用函数头插数据
	ListInsertHead(L, 520);
	ListInsertHead(L, 1314);
	ListInsertHead(L, 888);
	ListInsertHead(L, 999);

	//调用函数遍历链表
	ListShow(L);

	//调用函数插入数据
	ListInsertPos(L, 3, 2013);
	ListInsertPos(L, 4, 2014);
	ListInsertPos(L, L->len+1, 3344);
	
	//调用函数遍历链表
	ListShow(L);

	//调用函数头删数据
	ListDeleteHead(L);
	ListDeleteHead(L);

	//调用函数遍历链表
	ListShow(L);

	//调用函数删除数据
	ListDeletePos(L, 2);
	ListDeletePos(L, 3);
	ListDeletePos(L, L->len);
	
	//调用函数遍历链表
	ListShow(L);

	//调用函数按值查找位置
	int res = ListSearchValue(L, 2013);
	if(res !=-1)
	{
		printf("你要找的数据在链表的第%d个位置\n\n", res);
	}

	//掉用函数按位置修改
	ListUpdatePos(L, 2, 3344);

	//调用函数遍历链表
	ListShow(L);

	//掉用函数按值修改
	ListUpdateValue(L, 3344, 2014);

	//调用函数遍历链表
	ListShow(L);
	
	//调用函数反转链表
	ListReverse(L);

	//调用函数遍历链表
	ListShow(L);

	//调用函数头插数据
	ListInsertHead(L, 520);
	ListInsertHead(L, 520);
	ListInsertHead(L, 520);
	ListInsertHead(L, 1314);
	ListInsertHead(L, 1314);
	ListInsertHead(L, 1314);

	//调用函数遍历链表
	ListShow(L);
	
	//调用函数排序链表
	ListSort(L);

	//调用函数遍历链表
	ListShow(L);

	//调用函数反转链表(递归)
    L->next = ListReverseRecursion(L->next);

	//调用函数遍历链表
	ListShow(L);

	//调用函数去重链表
	ListDeduplication(L);

	//调用函数遍历链表
	ListShow(L);

	//调用函数释放链表
	ListFree(L);
	L = NULL;
	
	return 0;
}

4>程序运行截图

二、链表相关知识思维导图

1.链表

2.单向链表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值