一、链表相关练习
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.单向链表