以下链表函数均为不含虚拟头结点的链表。
目录
(1.头文件和结构体)
//引入的头文件
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
//结构体
typedef struct Node {
int data;
struct Node* pnext;
}N, * P;
2.尾插法
//尾插法:在链表末尾插入一个值为newval的新结点
void input(P ph, int newval) {
if (ph == NULL)
;
else{
//第一步:创建结点
P p1 = (P)malloc(sizeof(N));
if (p1 == NULL) {
printf("内存分配失败\n");
exit(-1);
}
p1->data = newval;
p1->pnext = NULL;
//第二步:遍历到链尾
while (ph->pnext) {
ph = ph->pnext;
}
//第三步:插入
ph->pnext = p1;
}
}
3.根据用户输入创建链表
//调用尾插法创建不含虚拟头结点的链表
P createph() {
P ph = (P)malloc(sizeof(N));
if (ph == NULL) {
printf("内存分配失败\n");
exit(-1);
}
ph->pnext = NULL;
int a;
//要使头结点存放有效数据,则需另外写个if语句
if (scanf("%d", &a))
if (a == 0) {
return NULL;
}
ph->data = a;
//输入特殊值0或任何错误的数据都会终止链表的创建
while (scanf("%d", &a)) {
if (a == 0) {
break;
}
input(ph, a);
}
//返回不含虚拟头结点的链表
return ph->pnext;
}
4.头插法
//头插法
void input_head(P ph, int newval) {
if (ph == NULL)
;
else{
//第一步:创建结点
P p1 = (P)malloc(sizeof(N));
if (p1 == NULL) {
printf("内存分配失败\n");
exit(-1);
}
p1->data = newval;
p1->pnext = NULL;
//第二步:易址
p1->pnext = ph->pnext;
//第三步:头结点插入
ph->pnext = p1;
}
}
5.求链表长度
//求链表中有效结点的个数(包括头指针)
int lenph(P ph) {
int len = 0;
while (ph) {
len++;
ph = ph->pnext;
}
return len;
}
6.在下标为index的结点前插入一个结点
//insert函数:在下标为index的结点前插入一个值为newval的结点
bool insert(P ph, int index, int newval) {
//第一步:判断
if (index <= 0 || index > lenph(ph) + 1 || ph == NULL) {
return false;
}
//第二步:创建
P p1 = (P)malloc(sizeof(N));
if (p1 == NULL) {
printf("内存分配失败\n");
exit(-1);
}
p1->data = newval;
//第三步:遍历到前一个结点,从i=0遍历到i<index-1
int i = 0;
for (; i < index - 1; i++) {
ph = ph->pnext;
}
//第四步:分别易址
p1->pnext = ph->pnext;
ph->pnext = p1;
return true;
}
7.遍历输出
//showph函数:遍历输出链表(输出头结点)
void showph(P ph) {
if (ph == NULL)
;
else{
while (ph) {
printf("%d\n", ph->data);
ph = ph->pnext;
}
}
}
8.查找下标为index的结点
//find_index函数:查找下标为index的结点
P find_index(P ph, int index) {
//第一步:判断下标
if (index <= 0 || index > lenph(ph))
return false;
//第二步:遍历到前一个结点,从i=0遍历到i<index-1
int i = 0;
for (; i < index - 1; i++) {
ph = ph->pnext;
}
return ph->pnext;
}
9.将值为value的结点改为newval
//find_val函数:将值为val的结点改为newval
bool find_val(P ph, int val, int newval) {
//检查
if (ph == NULL)
return false;
while (ph) {
//若成功修改,返回true
if (ph->data == val) {
ph->data = newval;
return true;
}
ph = ph->pnext;
}
//如果没有找到值为val的结点,返回false
return false;
}
10.快慢指针法找中间结点
//find_mid函数:快慢指针法查找链表的中间结点
P find_mid(P ph) {
P fast, slow;
fast = slow = ph;
while (fast && (fast->pnext)) {
//这样写的话,若结点数为偶数则返回第二个中间结点的指针
slow = slow->pnext;
fast = fast->pnext->pnext;
//如果加上这个if语句的话,若结点数为奇数则返回第一个中间结点的指针
if (fast->pnext->pnext == NULL)
break;
}
return slow;
}
11.机械合并两个链表
//merge_simple函数:机械合并两个链表,返回新表
P merge_simple(P ph1, P ph2) {
P p = ph1;
while (ph1->pnext) {
ph1 = ph1->pnext;
}
ph1->pnext = ph2;
return p;
}
12.合并两个有序链表
//merge_order函数:合并两个有序链表,返回新的有序链表(这里ph1,ph2,ptail都从小到大排序)
P merge_order(P ph1, P ph2) {
if (ph1 == NULL) {
return ph1;
}
if (ph2 == NULL) {
return ph2;
}
//ptail的作用是建立排序后的链表
P ph, ptail = (P)malloc(sizeof(N));
//因为到最后ptail已经指向了有序链表的末尾,所以ph的作用是储存头结点的地址
ph = ptail;
//开始遍历:当ph1或ph2任意一个遍历到末尾就停止了
while (ph1 && ph2) {
//如果把下面的小于号改为大于号,ph1,ph2都是从大到小,那么ptail将从大到小排序
if (ph1->data > ph2->data) {
ptail->pnext = ph1; //把ph1连接到ptail末尾
ptail = ptail->pnext; //ptail移动
ph1 = ph1->pnext; //ph1移动
}
else {
ptail->pnext = ph2; //把ph2连接到ptail末尾
ptail = ptail->pnext; //ptail移动
ph2 = ph2->pnext; //ph2移动
}
}
//若ph1非空,把ph1连接到ptail末尾
if (ph1 != NULL) {
ptail->pnext = ph1;
}
//若ph2非空,把ph2连接到ptail末尾
if (ph2 != NULL) {
ptail->pnext = ph2;
}
//销毁这个虚拟头结点
//P p0 = ph->pnext;
//free(ph);
//返回虚拟头结点的pnext值
return ph->pnext;
}
13.归并排序
//归并排序
//merge_order函数:合并两个有序链表,返回新的有序链表(这里ph1,ph2,ptail都从小到大排序)
P merge_order(P ph1, P ph2) {
//检查
if (ph1 == NULL) {
return ph1;
}
if (ph2 == NULL) {
return ph2;
}
//第一步:ptail和ph
//ptail的作用是建立排序后的链表
P ph, ptail = (P)malloc(sizeof(N));
//因为到最后ptail已经指向了有序链表的末尾,所以ph的作用是储存头结点的地址
ph = ptail;
//第二步:遍历:当ph1或ph2任意一个遍历到末尾就停止了
while (ph1 && ph2) {
//如果把下面的小于号改为大于号,ph1,ph2都是从大到小,那么ptail将从大到小排序
if (ph1->data > ph2->data) {
ptail->pnext = ph1; //把ph1连接到ptail末尾
ptail = ptail->pnext; //ptail移动
ph1 = ph1->pnext; //ph1移动
}
else {
ptail->pnext = ph2; //把ph2连接到ptail末尾
ptail = ptail->pnext; //ptail移动
ph2 = ph2->pnext; //ph2移动
}
}
//第三步:尾部处理
//若ph1非空,把ph1连接到ptail末尾
if (ph1 != NULL) {
ptail->pnext = ph1;
}
//若ph2非空,把ph2连接到ptail末尾
if (ph2 != NULL) {
ptail->pnext = ph2;
}
//第四步:释放
//P p0 = ph->pnext;
//free(ph);
//第五步:返回虚拟头结点的pnext值
return ph->pnext;
}
//find_sort函数:配合merge_order函数实现归并排序
P find_sort(P ph, P ptail) {
//检查
if (ph == NULL) {
return ph;
}
//第一步:若头尾相连,返回头
if (ph->pnext == ptail) {
ph->pnext = NULL;
return ph;
}
//第二步:快慢指针
P fast, slow;
fast = slow = ph;
while (fast != ptail && fast && (fast->pnext)) {
slow = slow->pnext;
fast = fast->pnext->pnext;
}
//第三步:返回slow
P mid = slow;
return merge_order(find_sort(ph, mid), find_sort(mid, ptail));
}
//find_sort0函数:归并排序的入口,先调用上一个函数分割链表
P find_sort0(P ph) {
return find_sort(ph, NULL);
}
14.删除下标为index的结点
//del函数:把以pheard为头指针的链表中(包含头结点)下标为index的结点删除
bool del(P ph, int index) {
//第一步:判断下标
if (index <= 0 || index > lenph(ph) || ph)
return false;
//第二步:遍历到前一个结点,从i=0遍历到i<index-1
int i = 0;
for (; i < index - 1; i++) {
ph = ph->pnext;
}
//第三步:保存了后一个结点
P p0 = ph->pnext->pnext;
//第四步:free掉该结点
//P p1 = ph->pnext;
//free(p1);
//第五步:易址
ph->pnext = p0;
return true;
}
15.删除值为val的结点
//del2函数:删除链表中的值为val的元素,返回新的头结点
P del2(P ph, int val) {
if (ph == NULL)
return ph;
P p0 = ph;
while (ph->pnext) {
if (ph->pnext->data == val) {
ph->pnext = ph->pnext->pnext;
//free(ph->pnext);
}
ph = ph->pnext;
}
return p0;
}
16.删除有序链表的重复元素
//del3函数:删除有序链表中的重复元素,返回新的头结点
P del3(P ph) {
if (ph == NULL)
return ph;
P pnow = ph;
while (pnow->pnext) {
if (pnow->data == pnow->pnext->data) {
pnow->pnext = pnow->pnext->pnext;
//free另外考虑
}
else
pnow = pnow->pnext;
}
return ph;
}
17.删除任意一个链表的重复元素
//del4函数:删除任意链表中的重复元素,返回新的头结点
P del4(P ph) {
if (ph == NULL)
return ph;
P pre, pnow, pnex;
pnow = ph;
//pnow作外层循环
while (pnow) {
//pnex在前,pre在后
pre = pnow;
pnex = pnow->pnext;
//pnex作内层循环
while (pnex) {
if (pnow->data == pnex->data)
pre->pnext = pnex->pnext;
//free另外考虑
else
pre = pnex;
pnex = pnex->pnext;
}
pnow = pnow->pnext;
}
return ph;
}
18.创建新链表法 倒置链表
//invert函数:创建新链表辅助倒置链表,返回新的头指针
P invert(P ph) {
//ph2是指针ph的影子
P ph2 = NULL;
//pnow是临时变量,新旧两边跑
P pnow = ph;
//pnex先行遍历原链表
P pnex = NULL;
while (ph) {
//三个变量做交换,ph->pnext被夹在中间
pnex = pnow->pnext;
pnow->pnext = ph2;
ph2 = pnow;
pnow = pnex;
}
return ph2;
}
19.就地倒置链表
//invert2函数:就地倒置链表
P invert2(P ph) {
if (ph == NULL)
return NULL;
P p1, p2, p3;
p1 = NULL;
p2 = ph;
p3 = ph->pnext;
//保持p1,p2,p3三个指针的顺序不变
while (p2) {
p2->pnext = p1; //倒置的关键步骤
p1 = p2;
p2 = p3;
//p3走在最前面,如果p3指向了空,就不移动了
if (p3)
p3 = p3->pnext;
}
return p1;
}