//1.预编译部分
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
//2.单链表的结构体
typedef struct LNode
{
int data;
struct LNode* next; //因为next指针指向的为结构体类型,所以类型为struct LNode*
}LNode, * LinkList; //代码没执行到最后一步之前,定义结构体还是要把类型名写全,之后才能简化为LNode
//3.单链表的初始化
void InitLinkList(LinkList L) //给头结点赋值
{
L->data = 0; //头结点的data域用作给链表长度计数
L->next = NULL; //头结点的next域用来指向链表的另一个节点
}
//4.单链表的打印
void PrintLinkList(LinkList L)
{
LNode* p; //定义一个结构体指针
p = L; //将它指向头指针的位置
while (p->next) //如果其下一个节点不为NULL
{
p = p->next; //则把这个指针往后一位,从而输出下一节点的值
printf("%d-->", p->data);
}
printf("NULL\n"); //如果其下一个节点为NULL,则输出NULL
}
//5.单链表的头插法
void HeadInsertLinkList(LinkList L)
{
LNode* NewNode; //新节点的地址
int data; //新节点中data的值
printf("请输入一个数,输入9999结束循环\n");
scanf("%d", &data);
//malloc()函数的作用为动态分配内存,分配内存的大小有内部参数sizeof()计算可得
//给静态地址赋值时要将其强制类型转换为相应指针类型
while (data != 9999)
{
//进行插入操作
//每次调用malloc函数,就重新在内存中开辟一块指定大小的内存空间给链表节点
NewNode = (LNode*)malloc(sizeof(LNode)); //相当于每次创建一个新的链表节点
NewNode->next = L->next; //将头指针中的next赋值给新创建的节点的next
L->next = NewNode; //将新建节点的地址赋值给头结点的next
NewNode->data = data; //将要输入的数赋值给新创建节点的data
L->data++; //头节点中的data+1,用来计数链表长度
//printf("请输入一个数,输入9999结束循环\n");
scanf("%d", &data);
}
}
//6.单链表的尾插法创建链表
void TailInsertLinkList(LinkList L)
{
LNode* NewNode; //新节点的地址
LNode* TailNode = L; //为了不改变头节点的位置,故定义一个尾节点来进行相关操作
int data; //新节点中data的值
while (TailNode->next != NULL) //当指向节点的下一个节点不为空时,尾节点一直向后走
{
TailNode = TailNode->next;
}
printf("请输入一个数,输入9999结束循环\n");
scanf("%d", &data);
while (data != 9999)
{
//进行插入操作
//每次调用malloc函数,就重新在内存中开辟一块指定大小的内存空间给链表节点
NewNode = (LNode*)malloc(sizeof(LNode)); //相当于每次创建一个新的链表节点
NewNode->data = data; //将数值插入新建节点的data
TailNode->next = NewNode; //将新建的节点连接在尾指节点之后
NewNode->next = NULL; //将新建节点的next赋值为空
TailNode = NewNode; //将尾节点向后一个节点
L->data++; //头节点中的data+1,用来计数链表长度
//printf("请输入一个数,输入9999结束循环\n");
scanf("%d", &data); //若输出9999跳出循环结束链表的创建
}
}
//7.按位查找数据元素
LNode* GetElem(LinkList L, int i)
{
//(1)判断i的合法性
if (i == 0) //链表为空
{
printf("你寻找的元素不存在,将返回头结点\n");
}
if (i<1 || i>L->data) //当i的位置小于1或大于表长,数据非法
{
printf("你寻找的元素不存在,将返回NULL\n");
}
//2.查找数据元素
LNode* p = L; //为了不改变头节点的位置,故定义一个查询节点来进行相关操作
for (int j = 1; j <= i; j++) //移动次数相应位数的次数
{
p = p->next; //查询节点后移,第一位是头结点
}
return p; //找到目标节点后返回这个节点
}
//8.按值查找数据元素
int* LocatElem(LinkList L, int e, int* count)
{
if (!L->next) //链表为空则返回头结点
{
printf("这个链表为空\n");
return 0;
}
LNode* p = L; //为了不改变头节点的位置,故定义一个查询节点来进行相关操作
while (p->next) //如果查询节点的下一个节点不为空
{
(*count)++; //计数器+1
p = p->next; //第一个节点为头结点,需要往后一个节点再判断
if (p->data == e)
{
return count;
}
}
printf("你寻找的元素不存在\n");
return 0;
}
//9.单链表的按位插入
void LocalInsertLinkList(LinkList L, int i, int e)
{
//(1)判断i的合法性
if (i<1 || i>(L->data + 1))
{
printf("要插入的元素的位置无效\n");
}
//插入新元素
LNode* p = GetElem(L, i - 1);
LNode* NewNode = (LNode*)malloc(sizeof(LNode));
NewNode->data = e;
NewNode->next = p->next;
p->next = NewNode;
L->data++;
}
//10.单链表的按位删除
void LocalDeletElem(LinkList L, int i, int* e)
{
//(1)检查i的合法性
if (!L->next)
{
printf("这个链表为空\n");
*e = 9999;
goto x;
}
if (i<1 || i>(L->data))
{
printf("要删除的元素不存在\n");
*e = 9999;
goto x;
}
//(2)删除指定元素
LNode* p = GetElem(L, i - 1);
LNode* q = p->next;
p->next = q->next;
*e = q->data;
free(q);
L->data--;
x:;
}
//11.销毁单链表
void DestoryLinkList(LinkList L)
{
int o;
while (L->data)
{
LocalDeletElem(L, 1, &o);
PrintLinkList(L);
}
free(L);
}
//12.单链表的合并
LinkList mergeList(LinkList L1, LinkList L2)
{
LinkList L3 = (LNode*)malloc(sizeof(LNode));
LNode* P1 = L1->next;
LNode* P2 = L2->next;
LNode* P3 = L3; //防止改变头结点的位置,新建一个节点和头结点指向同一位置,代替指针完成链表的链接
while (P1 != NULL && P2 != NULL)
{
if (P1->data <= P2->data)
{
P3->next = P1;
P1 = P1->next;
}
else
{
P3->next = P2;
P2 = P2->next;
}
P3 = P3->next;
}
P3->next = P1 == NULL ? P2 : P1;
return L3;
}
//合并两个单链表(相同元素保留一个)
LinkList Merge_List(LinkList La, LinkList Lb)/*合并以La,Lb为头结点的两个有序链表*/
{
LNode* Lc, * pa, * pb, * ptr;
LNode* pc = (LNode*)malloc(sizeof(LNode));
Lc = La;
pc = La;
pa = La->next;
pb = Lb->next;
while (pa != NULL && pb != NULL)
{
if (pa->data < pb->data)
{
pc->next = pa;
pc = pa;
pa = pa->next;
}
if (pa->data > pb->data)
{
pc->next = pb;
pc = pb;
pb = pb->next;
}
if (pa->data == pb->data)
{
pc->next = pa;
pc = pa;
pa = pa->next;
ptr = pb;
pb = pb->next;
free(ptr);
}
}
if (pa != NULL)
pc->next = pb;
else
pc->next = pb;
free(Lb);
return(Lc);
}
//单链表的逆置
LinkList converse(LinkList head)
{
LinkList p, q;
p = head->next;
head->next = NULL;
while (p)
{
/*向后挪动一个位置*/
q = p;
p = p->next;
/*头插*/
q->next = head->next;
head->next = q;
}
}
int main()
{
LinkList L1; //L是一个结构体指针——为头指针
L1 = (LNode*)malloc(sizeof(LNode)); //申请内存只能在主函数中完成,放在(除结构体指针类型)的自定义函数中时会随着函数的调用结束内存释放而失效
//给头结点赋值
//InitLinkList(L1);
//头插法创建链表
//HeadInsertLinkList(L1);
打印链表
//PrintLinkList(L1);
//_______________________________________________________________________
//给头结点赋值
InitLinkList(L1);
//尾插法创建链表
TailInsertLinkList(L1);
//打印链表
PrintLinkList(L1);
LinkList L2;
L2 = (LNode*)malloc(sizeof(LNode));
//给头结点赋值
InitLinkList(L2);
//尾插法创建链表
TailInsertLinkList(L2);
//打印链表
PrintLinkList(L2);
//_______________________________________________________________________
//按位查找数据元素
int i;
printf("请输入需要查找的位数\n");
scanf("%d", &i);
printf("链表L1第%d位的data=%d\n", i, GetElem(L1, i)->data);
//_______________________________________________________________________
//按值查找数据元素
int e;
int count = 0;
printf("请输入需要查找的数据\n");
scanf("%d", &e);
printf("%d在链表L1的第%d位\n", e, *(LocatElem(L1, e, &count)));
//_______________________________________________________________________
//单链表的按位插入
int n = 0;
int m = 0;
printf("请输入要插入的位置\n");
scanf("%d", &n);
printf("请输入要插入的值\n");
scanf("%d", &m);
LocalInsertLinkList(L1, n, m);
PrintLinkList(L1);
//_______________________________________________________________________
//单链表的按位删除
int d;
int q;
printf("请输入需要删除的位数\n");
scanf("%d", &q);
LocalDeletElem(L1, q, &d);
PrintLinkList(L1);
//_______________________________________________________________________
//销毁单链表
/*DestoryLinkList(L1);*/
//—————————————————————————————————————
//合并单链表
printf("合并后的单链表:\n");
LinkList h;
h = Merge_List(L1, L2);
PrintLinkList(h);
//单链表的逆置
//打印链表
printf("逆置后的链表\n");
PrintLinkList(converse(h));
return 0;
}