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;
}
相关推荐
xchenhao7 小时前
基于 Flutter 的开源文本 TTS 朗读器(支持 Windows/macOS/Android)
android·windows·flutter·macos·openai·tts·朗读器
帽儿山的枪手8 小时前
追踪网络流量就这么简单 | 进阶篇 | conntrack
linux·windows·网络协议
兮动人10 小时前
Windows 11 系统关键文件夹详解及安全清理指南
windows·安全
LabVIEW开发14 小时前
LabVIEW调用外部DLL
windows·labview·labview知识·labview功能·labview程序
biubiubiu070614 小时前
FFmpeg Windows安装
windows·ffmpeg
哆啦A梦——16 小时前
dll文件缺失解决方法
windows
漠效17 小时前
Duplicate cleaner pro 的使用技巧
windows·经验分享
DogDaoDao17 小时前
Windows下VScode配置FFmpeg开发环境保姆级教程
windows·vscode·ffmpeg·音视频·gcc
Rudon滨海渔村18 小时前
exe文件图标修改器 - exe图标提取器(ico、png) - 修改360文件夹的图标为windows自带的图标
windows
无名小猴19 小时前
Windows软件卸载
windows