C语言链表相关函数(VS2019)

以下链表函数均为不含虚拟头结点的链表。

目录

(1.头文件和结构体)

2.尾插法 

3.根据用户输入创建链表 

4.头插法 

5.求链表长度 

6.在下标为index的结点前插入一个结点 

7.遍历输出 

8.查找下标为index的结点 

 9.将值为value的结点改为newval

10.快慢指针法找中间结点 

11.机械合并两个链表 

12.合并两个有序链表 

13.归并排序 

14.删除下标为index的结点 

15.删除值为val的结点 

16.删除有序链表的重复元素 

17.删除任意一个链表的重复元素 

18.创建新链表法 倒置链表 

19.就地倒置链表 


(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;
}

  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值