当前位置: 首页 > news >正文

C语言--常用的链表操作

利用C语言实现链表,并定义一些常用的操作

文章目录

  • 链表定义
  • 新建一个链表结点
  • 打印链表
  • 插入结点
    • 头插法(常用)
      • 运行
    • 尾插法(使用较少)
      • 运行
  • 返回链表长度
  • 链表转置
    • 运行
  • 合并两个有序的链表
    • 运行
  • 删除最小结点
    • 运行
  • 打印倒数第k个元素
    • 运行
  • 循环右移k个位置
    • 运行
  • 判断链表是否有环
    • 运行

链表定义

使用typedef简化代码

#include <stdio.h>
#include <stdlib.h>

typedef struct LinkedList {
    int data;
    struct LinkedList *next;
} LinkedList;

新建一个链表结点

LinkedList *createLinkedList(int i) {
    LinkedList *list = (LinkedList *)malloc(sizeof(LinkedList));
    list->data = i;
    list->next = NULL;
    return list;
}

打印链表

void printAll(LinkedList *head) {
    LinkedList *current = head;
    while (current != NULL) {
        printf(" --->%d", current->data);
        current = current->next;
    }
    printf("\n");
}

插入结点

头插法(常用)

采用头插法产生的链表和输入的数字是逆序的。
例如:一次插入1,2,3,4,5。链表为:5–>4 -->3 -->2 -->1

LinkedList **p 是指向指针的指针,用于直接修改调用者作用域中的头指针。如果采用LinkedList *p那么只能修改指针中的数值,而不能直接修改头指针,那么头插法也就没法实现了。

void insertAtHead(LinkedList **p, int data) {
    LinkedList *newNode = malloc(sizeof(LinkedList));
    newNode->data = data;
    newNode->next = *p;
    *p = newNode;
}

运行

int main() {
    LinkedList *head2 = NULL;
    insertAtHead(&head2, 1);
    insertAtHead(&head2, 2);
    insertAtHead(&head2, 3);
    insertAtHead(&head2, 4);
    printAll(head2);
    
    return 0;
}

在这里插入图片描述

尾插法(使用较少)

遍历到最后一个结点,然后把目标结点挂到链表上

void insertAtTail(LinkedList **p, int data) {
    LinkedList *newNode = malloc(sizeof(LinkedList));
    newNode->data = data;
    newNode->next = NULL;

    if (*p == NULL) {
        *p = newNode;
    }else {
        LinkedList *current = *p;
        // 遍历到最后一个节点
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = newNode;
    }
}

运行

与头插法顺序恰恰相反

int main() {
    LinkedList *head2 = NULL;
    insertAtTail(&head2, 1);
    insertAtTail(&head2, 2);
    insertAtTail(&head2, 3);
    insertAtTail(&head2, 4);
    printAll(head2);

    return 0;
}

在这里插入图片描述

返回链表长度

int lengthOfNode(LinkedList *head) {
    int length = 0;
    LinkedList *current = head;
    while (current != NULL) {
        length++;
        current = current->next;
    }
    return length;
}

链表转置

采用三指针法,每次循环保存prev和next,实现局部转置,直到全部结点都实现转置。此时current为NULL,prev刚好指向最后一个元素,也就是转置后的第一个元素,使其为头节点即可。

void reverseList(LinkedList **head) {
    LinkedList *current = *head;
    LinkedList *prev = NULL;
    LinkedList *next = NULL;
    while (current != NULL) {
       
        next = current->next; // 保存next
        current->next = prev; // 实现局部转置

        prev = current;
        current = next;
    }
    *head = prev;
}

运行

int main() {
    LinkedList *head2 = NULL;
    insertAtHead(&head2, 1);
    insertAtHead(&head2, 3);
    insertAtHead(&head2, 5);
    insertAtHead(&head2, 6);
    insertAtHead(&head2, 99);
    
    printAll(head2);
    reverseList(&head2);
    printAll(head2);

    return 0;
}

在这里插入图片描述

合并两个有序的链表

创建一个临时链表,当两个链表都不为空时,比较链表结点大小,总是将值小的链表结点挂到临时链表上,当有一个链表为空时,直接将剩下的那个链表结点全部挂到临时链表即可。

LinkedList *mergeList(LinkedList *a, LinkedList *b) {
    LinkedList *pHead = malloc(sizeof(LinkedList));
    pHead->data = -1;
    LinkedList *current = pHead;

    while (a!=NULL && b!=NULL) {
        LinkedList *tmp = malloc(sizeof(LinkedList));
        if (a->data < b->data) {
            tmp->data = a->data;
            current->next = tmp;

            current = current->next;
            a = a->next;
        }else {
            tmp->data = b->data;
            current->next = tmp;
            current = current->next;
            b = b->next;
        }
    }

    if (a!=NULL) {
        current->next = a;
    }

    if (b!=NULL) {
        current->next = b;
    }

    return pHead->next;
}

运行

int main() {

    LinkedList *head1 = NULL;
    insertAtTail(&head1, 1);
    insertAtTail(&head1, 3);
    insertAtTail(&head1, 8);
    printAll(head1);

    LinkedList *head2 = NULL;
    insertAtTail(&head2, 2);
    insertAtTail(&head2, 7);
    insertAtTail(&head2, 99);
    printAll(head2);

    printAll(mergeList(head1, head2));

    return 0;
}

在这里插入图片描述

删除最小结点

先创建一个值为-1的哑结点,为了简化对链表为NULL时的处理。
通过循环找到最小结点,并且记录最小结点的前结点。前结点下一个结点指向最小结点的下一个结点即可(跨过最小结点)

void deleteMinNode(LinkedList **head) {
     LinkedList *tmpHead = createLinkedList(-1);
     tmpHead->next = *head;

    LinkedList *cur = tmpHead->next;
    LinkedList *prev = tmpHead;

     LinkedList *prevMin = tmpHead;
     LinkedList *minNode = cur;
     while (cur != NULL) {
         if (cur->data < minNode->data) {
           prevMin = prev;
           minNode = cur;
         }
         prev = cur;
         cur = cur->next;
     }

     prevMin->next = minNode->next;
     *head = tmpHead->next;
}

运行

int main() {
    LinkedList *head1 = NULL;
    insertAtTail(&head1, 1);
    insertAtTail(&head1, 3);
    insertAtTail(&head1, 8);
    insertAtTail(&head1, 99);
    printAll(head1);
    deleteMinNode(&head1);
    printAll(head1);
    
    return 0;
}

在这里插入图片描述

int main() {

    LinkedList *head1 = NULL;
    insertAtTail(&head1, 88);
    insertAtTail(&head1, 3);
    insertAtTail(&head1, 8);
    insertAtTail(&head1, 99);
    printAll(head1);
    deleteMinNode(&head1);
    printAll(head1);

    return 0;
}

在这里插入图片描述

打印倒数第k个元素

利用快慢指针法,快指针先走k步;然后循环,快指针走到尾,慢指针刚好指向倒数第k个结点

void printLastKNode(LinkedList *head, int k) {
    LinkedList *current = head;
    LinkedList *slow = head;
    LinkedList *fast = NULL;
    while (k-->0) {
        fast = current->next;
        current = current->next;
    }
    while (fast != NULL) {
        slow = slow->next;
        fast = fast->next;
    }
    printf("--->%d", slow->data);
}

运行

int main() {

    LinkedList *head1 = NULL;
    insertAtTail(&head1, 88);
    insertAtTail(&head1, 3);
    insertAtTail(&head1, 8);
    insertAtTail(&head1, 99);

    printAll(head1);
    printLastKNode(head1, 1);
    printf("\n");
    printLastKNode(head1, 2);
    printf("\n");
    printLastKNode(head1, 4);

    return 0;
}

在这里插入图片描述

循环右移k个位置

将循环右移k个位置,例如k=2, 123456变为:561234
先找到分割结点的前一个结点,此时将链表断为两段,即:1–2–3–4–NULL 和 5–6–NULL
然后将后半段next指向前半段即可。

void rightCycleKNode(LinkedList **head, int k) {
    int length = 1;
    LinkedList *backNode = *head;
    while (backNode->next != NULL) {
        length++;
        backNode = backNode->next;
    }
    // now back is point at tail: 5--6--NULL
    int preK = length - k - 1;
    LinkedList *front = *head;
    LinkedList *newHead = NULL;
    // 找到分割结点的前一个结点,此时也可以快慢指针,先让快指针先走k步,然后快指针指向尾结点时,慢指针刚好指向分割结点的前一个结点
    while (preK-- > 0) {
        front = front->next;
    }
    // after loop, now node is point at 4

    newHead = front->next;  // 此时new: 5--6--NULL
    front->next = NULL; // cut front line: 1--2--3--4--NULL(head此时和front一样,只是指向的结点不一样)
    backNode->next = *head;  // 把1234接到6的后边,6--1--2

    *head = newHead;
}

运行

int main() {

    LinkedList *head1 = NULL;
    insertAtTail(&head1, 1);
    insertAtTail(&head1, 2);
    insertAtTail(&head1, 3);
    insertAtTail(&head1, 4);
    insertAtTail(&head1, 5);
    insertAtTail(&head1, 6);

    printAll(head1);
    rightCycleKNode(&head1, 2);
    printAll(head1);

    return 0;
}

在这里插入图片描述

判断链表是否有环

采用快慢指针法,快指针每次走两步,慢指针每次走一步,如果存在环,快指针最终会沿着环与慢指针相遇(类似于跑步中的套圈)

运行

int main() {

    LinkedList *head1 = NULL;
    insertAtTail(&head1, 1);
    insertAtTail(&head1, 2);
    insertAtTail(&head1, 3);

    hasCycle(head1);
    head1->next->next->next = head1;
    hasCycle(head1);

    return 0;
}

在这里插入图片描述

相关文章:

  • 分布式存储怎样提高服务器数据的安全性?
  • Vue3+Vite+TypeScript+Element Plus开发-09.登录成功跳转主页
  • CentOS8.5 LLaMA-Factory训练模型
  • ChatDBA:一个基于AI的智能数据库助手
  • 基于C8051F340单片机的精确定时1S的C程序
  • 代码随想录算法训练营--打卡day8
  • 状态同步梳理
  • 如何精准控制大模型的推理深度
  • 解密工业控制柜:认识关键硬件(PLC)
  • NO.84十六届蓝桥杯备战|动态规划-路径类DP|矩阵的最小路径和|迷雾森林|过河卒|方格取数(C++)
  • Stable Diffusion + Contronet,调参实现LPIPS最优(带生成效果+指标对比)——项目学习记录
  • Java接口性能优化面试问题集锦:高频考点与深度解析
  • 【设计模式】访问者模式
  • 微软庆祝它成立整整50周年
  • 将图片按照指定大小批量进行裁剪(可设置步长_python)
  • 怎样使用Python编写的Telegram聊天机器人
  • Android compose源码浅析——Modifier
  • Python第八章03:Pyecharts快速入门
  • excel中的VBA指令示例(一)
  • 考研单词笔记 2025.04.09
  • 如何打开建设网站后台/如何网络媒体推广
  • 做网站在阿里云上面买哪个服务/快速排名优化
  • asp做微网站设计/百度怎么打广告在首页
  • 做网站的软件去哪里买/网络营销方案范文
  • 西安网站建设公司/windows7优化大师
  • 福州专业做网站/百度的推广广告