2024.11.29(单链表)

思维导图

声明文件

#ifndef __LINKLIST_H__
#define __LINKLIST_H__

#include <myhead.h>

typedef char datatype; 	//数据元素类型
//定义节点类型
typedef struct Node
{
	union
	{
		int len; 		//头节点数据域
		datatype data; 	//普通节点数据域
	};

struct Node *next; //指针域

}Node ,*Node_ptr;

//创建链表
Node_ptr list_create();

//链表判空操作
int list_empty(Node_ptr L);

//定义申请节点封装数据函数
static Node_ptr node_apply(datatype e);

//单向链表头插
int list_insert_head(Node_ptr L,datatype e);

//单向链表的按位置查找返回节点
Node_ptr list_find_node(Node_ptr L,int pos);

//单链表遍历
void list_show(Node_ptr L);

//单向链表任意位置插入
int list_insert_anypos(Node_ptr L,int pos,datatype e);

//单链表头删
int  list_head_delete(Node_ptr L);

//任意位置删除
int list_delete_anywhere(Node_ptr L,int pos);

//按位置进行修改
int list_update_pos(Node_ptr L,int pos,datatype e);

//单向链表翻转
int list_reverse(Node_ptr L);

//销毁单链表
void list_destroy(Node_ptr L);

//单链表尾插
int list_insert_tail(Node_ptr L,datatype e);

//单链表的尾删
int list_delete_tail(Node_ptr L);

//单链表按值查找返回位置
int list_find_value(Node_ptr L,int e);

//单链表按值修改
int list_edit_value(Node_ptr L,int w,datatype e);

//单链表的排序
int list_sort(Node_ptr L);

//单链表的去重
int list_duplicate_removal(Node_ptr L);


//清空单链表
int list_clear(Node_ptr L);

//返回单链表的长度
int list_len(Node_ptr L);

#endif

测试文件

#include "linklist.h"
int main(int argc, const char *argv[])
{
	//调用链表创建函数
	Node_ptr L = list_create();
	if(NULL == L)
	{
		return -1;
	}
	//调用头插函数
	list_insert_head(L,'A');
	list_insert_head(L,'B');
	list_insert_head(L,'C');
	list_insert_head(L,'D');
	list_insert_head(L,'A');
	list_insert_head(L,'B');
	list_insert_head(L,'C');
	list_insert_head(L,'D');

	//调用遍历函数
	list_show(L);
	/*	
	//调用任意插入函数
	list_insert_anypos(L,1,'u');
	list_show(L);
	list_insert_anypos(L,L->len+1,'P');
	list_show(L);
	list_insert_anypos(L,3,'9');
	list_show(L);

	//调用头删函数
	list_head_delete(L);
	list_show(L);
	//调用任意位置删除
	list_delete_anywhere(L,3);
	list_show(L);
	list_delete_anywhere(L,2);
	list_show(L);

	//调用按位置修改函数
	list_update_pos(L,2,'H');
	list_show(L);

	//调用翻转函数
	list_reverse(L);
	list_show(L);

	//调用尾插法
	list_insert_tail(L,'e');
	list_show(L);

	//调用尾删除
	list_delete_tail(L);
	list_show(L);

	//调用按值查找函数
	int a = list_find_value(L,'H');
	printf("位置为%d\n",a);

	//调用单链表按值修改
	list_edit_value(L,'H','A');	
	list_show(L);

	//调用排序函数
	list_sort(L);
	list_show(L);
	
	//调用去重函数
	list_duplicate_removal(L);
	list_show(L);

printf("%d",L->len);
	//调用清空函数
	list_clear(L);
	list_show(L);
printf("%d",L->len);
	//调用销毁函数
	list_destroy(L);
	L = NULL;
	list_show(L);
	*/
	printf("链表长度为:%d\n",list_len(L));
	return 0;
}

功能函数文件

#include "linklist.h"
//创建链表
Node_ptr list_create()
{
	//在堆区申请一个头结点的空间
	Node_ptr L = (Node_ptr)malloc(sizeof(Node));
	if(L == NULL)
	{
		printf("创建失败\n");
		return NULL;
	}
	//程序执行至此,一个头结点就申请成功
	//有了头结点就有了一条2链表
	//初始化操作
	L->len = 0; 		//表示链表长度为0
	L->next = NULL; 	//防止野指针

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

}

//链表判空操作
//如果链表为空,返回1,非空返回0
int list_empty(Node_ptr L)
{
	//判断逻辑
	if(NULL == L)
	{
		printf("链表不合法\n");
		return -1;
	}
	return 0;

}

//定义申请节点封装数据函数
static Node_ptr node_apply(datatype e)
{
	//在堆区申请一个节点的空间
	Node_ptr P = (Node_ptr)malloc(sizeof(Node));
	if(NULL == P)
	{
		printf("节点申请失败\n");
		return NULL;
	}
	//将数据封装进节点的数据域
	P->data = e;
	P->next = NULL; 	//防止野指针
	return P; 			//将封装好的节点地址返回
}

//单向链表头插
int list_insert_head(Node_ptr L,datatype e)
{
	//判断逻辑
	if(NULL == L)
	{
		printf("链表不合法\n");
		return -1;
	}

	//申请节点封装数据
	Node_ptr P = node_apply(e);
	if(NULL ==P )
	{
		return -1;
	}
	//程序执行至此,表示节点申请成功

	//头插逻辑
	P->next = L->next;
	L->next = P;

	//表长变化
	L->len++;
	printf("插入成功\n");

}

//单向链表的按位置查找返回节点
Node_ptr list_find_node(Node_ptr L,int pos)
{
	//判断逻辑、
	if( NULL == L||pos <0||pos>L->len)
	{
		printf("查找失败\n");
		return NULL;
	}
	//查找逻辑
	Node_ptr Q = L; 		//定义遍历指针
	for(int i=0;i<pos;i++)
	{
		Q = Q->next; 		//将指针偏移到下一个节点位置
	}
	//返回节点
	return Q;

}

//单链表遍历
void list_show(Node_ptr L)
{
	//判断逻辑
	if(list_empty(L))
	{
		printf("遍历失败\n");
		return ;
	}
	/*遍历所有节点
	  printf("链表中的元素分别是:");
	  for(int i=1;i<L->len;i++)
	  {
	  Node_ptr Q = list_find_node(L,i); //找到第i个节点
	  printf("%c\t",Q->data);
	  }
	  */

	printf("链表中的元素分别是:");
	Node_ptr Q = L->next; //定义遍历指针从第一个节点出发
	/*
	   for(int i=0;i<L->len;i++)
	   {
	   Q = Q->next;
	   printf("%c\t",Q->data);
	   }
	   */
	while(Q)
	{
		//当前节点不为空,输出数据域
		printf("%c\t",Q->data);
		Q = Q->next; 	//继续遍历下一个节点
	}
	printf("输出完成\n");
}


//单向链表任意位置插入
int list_insert_anypos(Node_ptr L,int pos,datatype e)
{
	//判断逻辑
	if(pos>L->len+1||pos<1||NULL == L)
	{
		printf("插入失败\n");
		return -1;
	}
	//判断逻辑
	//找到要插入位置的前一个节点
	Node_ptr Q = list_find_node(L,pos-1);
	//插入逻辑
	Node_ptr W = node_apply(e);
	if(NULL == W)
	{
		return -1;
	}
	W->next = Q->next;
	Q->next = W;
	//表长变化
	L->len++;
	printf("插入成功\n");
}

//单链表头删
int  list_head_delete(Node_ptr L)
{
	//判断逻辑
	if(NULL == L||list_empty(L))
	{
		printf("删除失败\n");
		return -1;
	}
	Node_ptr Q = L->next;
	L->next = Q->next;
	free(Q);
	Q = NULL;

	//表长变化
	L->len--;
	printf("删除成功\n");
	return 0;
}

//任意位置删除
int list_delete_anywhere(Node_ptr L,int pos)
{
	//判断逻辑
	if(NULL==L||list_empty(L)||pos<1||pos>L->len)
	{
		printf("删除失败\n");
		return -1;
	}
	//删除逻辑
	Node_ptr Q = list_find_node(L,pos-1); 	//找到前驱
	Node_ptr W = Q->next; 	//标记要删除的节点
	Q->next = W->next; 		//孤立要删除的节点
	free(W); 				//释放要删除的节点
	W = NULL;
	//表长变化
	L->len--;
	printf("删除成功\n");
	return 0;
}

//按位置进行修改
int list_update_pos(Node_ptr L,int pos,datatype e)
{
	//判断逻辑	
	if(NULL==L||list_empty(L)||pos<1||pos>L->len)
	{
		printf("删除失败\n");
		return -1;
	}
	//查找指定节点
	Node_ptr Q = list_find_node(L,pos-1); 	//找到前驱
	//进行修改
	Q->data = e;
	printf("修改成功\n");
	return 0;
}

//单向链表翻转
int list_reverse(Node_ptr L)
{
	//判断逻辑	
	if(NULL==L||list_empty(L)||L->len == 1)
	{
		printf("翻转失败\n");
		return -1;
	}
	//翻转逻辑
	Node_ptr H = L->next; 	//用头指针托管链表
	L->next = NULL; 		//清空当前链表

	while(H!=NULL)
	{
		Node_ptr Q = H; 	//挖墙脚
		H= H->next; 		//管理下一位

		//以头插法的形式将Q插入到L中
		Q->next = L->next;
		L->next = Q;

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


//销毁单链表
void list_destroy(Node_ptr L)
{
	//判断逻辑
	if(NULL == L||L->next == NULL)
	{
		printf("销毁失败\n");
		return ;
	}
	Node_ptr Q = L->next;
	while(Q!=NULL)
	{
		Node_ptr temp = Q;
		Q = Q->next;
		free(temp);
	}
	L->next = NULL;
	printf("销毁成功\n");
	/*
	//释放逻辑
	//将所有普通节点释放
	while(!list_empty(L))
	{
	//调用头删除函数
	list_head_delete(L);
	}
	//释放头节点
	free(L);
	L = NULL;
	printf("销毁成功\n");
	*/
}

//单链表尾插
int list_insert_tail(Node_ptr L,datatype e)
{
	//判断逻辑
	if(NULL == L)
	{
		printf("单链表不合法\n");
		return -1;
	}
	//插入逻辑
	Node_ptr Q = list_find_node(L,L->len);
	Node_ptr W = node_apply(e);
	Q->next = W;
	//长度变化
	L->len++;
	printf("添加成功\n");
	return 0;
}

//单链表的尾删
int list_delete_tail(Node_ptr L)
{
	if(NULL == L||L->len<1)
	{
		printf("删除失败\n");
		return -1;
	}
	//删除逻辑
	Node_ptr Q = list_find_node(L,L->len-1);
	Node_ptr W = Q->next;
	Q->next = NULL;
	free(W);
	W = NULL;
	//长度变化
	L->len--;
	printf("删除成功\n");
	return 0;

}

//单链表按值查找返回位置
int list_find_value(Node_ptr L,int e)
{
	//判断逻辑
	if(NULL == L||list_empty(L))
	{
		printf("查找失败\n");
		return -1;
	}
	//查找逻辑
	Node_ptr Q = L->next;
	for(int i=0;i<L->len;i++)
	{
		if(Q->data == e)
		{
			printf("查找成功\n");
			return i+1;
		}
		Q = Q->next;
	}
	printf("未查找到该值\n");
	return 0;
}

//单链表按值修改
int list_edit_value(Node_ptr L,int w,datatype e)
{
	//判断逻辑
	if(NULL == L||list_empty(L))
	{
		printf("查找失败\n");
		return -1;
	}
	//修改逻辑
	int flag = 0; 		//检测是否修改
	Node_ptr Q = L->next;
	for(int i=0;i<L->len;i++)
	{
		if(Q->data == w)
		{
			flag = 1;
			Q->data = e;
		}
		Q = Q->next;
	}
	if(flag == 0)
	{
		printf("未查找到该值\n");
		return 0;
	}
	else
	{
		printf("修改成功\n");
		return 0;
	}

}

//单链表的排序
int list_sort(Node_ptr L)
{
	if(NULL == L||list_empty(L))
	{
		printf("排序失败\n");
		return -1;
	}
	//排序逻辑
	Node_ptr Q = NULL;
	Node_ptr T = NULL;
	Node_ptr W = NULL;

	//冒泡排序
	for(int i=1;i<L->len;i++)
	{
		Q = L;
		T = Q->next;
		W = T->next;

		for(int j=0;j<L->len-i;j++)
		{

			//升序
			if(T->data > W->data)
			{
				T->next = W->next;//链接后面节点
				W->next = Q->next;
				Q->next = W;
				//便于下次交换
				Q=Q->next;
				//p已经被交换到后面
				W = T->next;
			}
			else
			{
				//不满足条件继续后移比较
				Q = Q->next;
				T = T->next;
				W = W->next;
			}
		}
	}
	return 0;
}

//单链表的去重
/*
int list_duplicate_removal(Node_ptr L)
{
	if(NULL == L||L->len<2||list_empty(L))
	{
		printf("去重失败\n");
		return -1;
	}
	//去重逻辑
	Node_ptr Q = L;
	Node_ptr T = NULL;
	Node_ptr W = NULL;
	//外层循环避免多个重复元素,控制趟数
for(int i=1;i<L->len-1;i++)
	//for(int i=1;Q!=NULL||Q->next !=NULL;i++)
	{
		T = Q;//内层循环结束,重新指向
		W = Q->next;
		for(int j=0;j<L->len-2-i;j++)
		//for(int j=0;W!=NULL;j++)
		{
			if(T->data == W->data)
			{
				Node_ptr Temp = W->next;
				free(W);//删除重复部分,释放内存
				T->next = Temp;
				//长度变化
				L->len--;
				printf("%d\n",L->len);
			}
			else
			{
				W = W->next; //移动到下一个节点
			}
		}
		Q = Q->next;//内层循环结束向前移动一次
	}
	printf("去重成功\n");
	return 0;
}
*/
int list_duplicate_removal(Node_ptr L) {
    if (NULL == L || L->len < 2 || list_empty(L)) {
        printf("去重失败\n");
        return -1;
    }

    Node_ptr T, W, prev;
    int i;

    // 遍历链表,T为当前节点,W为T的下一个节点
    for (T = L->next, prev = L; T != NULL && T->next != NULL; ) {
        W = T->next; // W指向T的下一个节点

        // 检查W是否与T之后的节点有重复
        while (W != NULL) {
            if (T->data == W->data) {
                Node_ptr temp = W->next; // 保存W的下一个节点
                prev->next = temp; // 跳过W节点
                free(W); // 释放W节点的内存
                L->len--; // 更新链表长度
                W = temp; // W更新为新的节点,继续检查
            } else {
                prev = W; // 更新prev为W,W移动到下一个节点
                W = W->next;
            }
        }

        T = T->next; // T移动到下一个节点
    }

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

//清空单链表
int list_clear(Node_ptr L)
{
	if(NULL == L||list_empty(L))
	{
		printf("单链表不存在或为空\n");
		return -1;
	}
	while(L->next!=NULL)
	{
		list_head_delete(L);
	}
	printf("清空完成\n");
	return 0;
}
//返回单链表的长度
int list_len(Node_ptr L)
{
	if(NULL == L)
	{
		printf("该链表不存在\n");
		return -1;
	}
	Node_ptr Q = L->next;
	int num = 0;
	while(Q)
	{
		Q = Q->next;
		num++;
	}
	return num;
}
相关推荐
我叫安查查34 分钟前
win10系统部署RAGFLOW+Ollama教程
windows·语言模型·llama
小程序耿4 小时前
常见Linux命令(详解)
linux·服务器·windows
㎝㎜8 小时前
Windows系统搭建Docker
windows·docker·容器
spencer_tseng12 小时前
LuaForWindows_v5.1.5-52.exe
windows·lua
APItesterCris19 小时前
对于大规模的淘宝API接口数据,有什么高效的处理方法?
linux·服务器·前端·数据库·windows
Narutolxy21 小时前
实现跨平台 SSH 连接:从 macOS 到 Windows WSL 的完整解决方案20241203
windows·macos·ssh
Lill_bin1 天前
BeanUtils:Java Bean工具类详解
java·开发语言·windows·python·算法·servlet
qq_338432371 天前
win11 多任务 贴靠 bug:左右两窗口贴靠时拖动中间的对齐条后,资源管理器有概率卡死
windows·bug
团团爱吃水果1 天前
Vivado安装双击xsetup没反应解决办法
windows