C语言入门基础之链表和指针:指针链表速成

本文介绍了C语言中链表和指针的基础知识,包括指针的概念和使用,链表的创建、遍历、插入、删除、反转等操作,以及双指针法、循环链表、头插法和尾插法。同时,文章还涉及了如何释放链表内存,提供代码示例帮助理解。
摘要由CSDN通过智能技术生成

导语: 在C语言编程中,链表和指针是两个重要的概念。理解它们的使用方法和原理对于提高编程能力至关重要。本篇博客将以九个重要点来介绍C语言链表和指针,帮助你快速掌握它们的基本知识和应用。每个点都会配上相应的代码示例,让你更好地理解这些概念。让我们一起来学习吧!

一、指针的基本概念与使用

在C语言中,指针是一种特殊的变量,用于存储内存地址。通过指针,我们可以直接访问和修改内存中的数据。在使用指针之前,需要明确指针的声明、初始化和使用方法,例如通过*操作符解引用指针,获取指针所指向的值。下面是一个简单的示例代码:

 
#include <stdio.h>

int main() {
    int num = 10;
    int* ptr = &num;  // 声明并初始化指针

    printf("Value: %d\n", *ptr);  // 解引用指针输出值
    return 0;
}

二、链表的基本概念与创建

链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。相对于数组,链表的长度可以动态改变,更适合处理动态数据。创建链表的第一个节点称为头节点。下面是一个简单的链表创建示例代码:

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

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

int main() {
    Node* head = NULL;  // 初始化头节点
    Node* second = NULL;
    Node* third = NULL;

    head = (Node*)malloc(sizeof(Node));
    second = (Node*)malloc(sizeof(Node));
    third = (Node*)malloc(sizeof(Node));

    head->data = 1;
    head->next = second;

    second->data = 2;
    second->next = third;

    third->data = 3;
    third->next = NULL;

    return 0;
}

三、链表的遍历和插入

遍历链表是指按顺序访问链表中的每个节点。我们可以使用循环来实现链表的遍历,直到指针指向最后一个节点为止。链表的插入操作可以在任意位置插入新的节点,需要修改相应节点的指针。下面是一个遍历链表并插入新节点的示例代码:

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

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

void insert(Node** head, int value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = *head;
    *head = newNode;
}

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

int main() {
    Node* head = NULL;

    insert(&head, 3);
    insert(&head, 2);
    insert(&head, 1);

    traverse(head);  // 输出:1 2 3

    return 0;
}

C语言链表详解(通俗易懂,超详细)_一坨牛马的博客-CSDN博客_c语言链表结构

 

四、链表的删除操作

链表的删除操作可以删除指定节点或满足某个条件的节点。删除操作需要修改相应节点的指针,确保链表的连续性。下面是一个删除链表节点的示例代码:

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

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

void delete(Node** head, int key) {
    Node* current = *head;
    Node* previous = NULL;

    if (current != NULL && current->data == key) {
        *head = current->next;
        free(current);
        return;
    }

    while (current != NULL && current->data != key) {
        previous = current;
        current = current->next;
    }

    if (current == NULL)
        return;

    previous->next = current->next;
    free(current);
}

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

int main() {
    Node* head = NULL;

    // 创建链表

    traverse(head);  // 输出:1 2 3

    delete(&head, 2);  // 删除节点

    traverse(head);  // 输出:1 3

    return 0;
}

五、指针链表的反转

反转链表是指将链表中的节点顺序颠倒,使原先指向后继节点的指针指向前驱节点。这需要修改节点的指针指向来实现。下面是一个反转链表的示例代码:

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

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

void reverse(Node** head) {
    Node* previous = NULL;
    Node* current = *head;
    Node* next = NULL;

    while (current != NULL) {
        next = current->next;
        current->next = previous;
        previous = current;
        current = next;
    }

    *head = previous;
}

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

int main() {
    Node* head = NULL;

    // 创建链表

    traverse(head);  // 输出:1 2 3

    reverse(&head);  // 反转链表

    traverse(head);  // 输出:3 2 1

    return 0;
}

六、双指针法解决链表问题

在解决链表问题时,双指针法是一种常用的技巧。通过使用两个指针,可以在遍历链表时快速找到目标节点或处理特定问题。下面是一个使用双指针法找到链表中间节点的示例代码:

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

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

Node* findMiddle(Node* head) {
    Node* slowPtr = head;
    Node* fastPtr = head;

    while (fastPtr != NULL && fastPtr->next != NULL) {
        slowPtr = slowPtr->next;
        fastPtr = fastPtr->next->next;
    }

    return slowPtr;
}

int main() {
    Node* head = NULL;

    // 创建链表

    Node* middle = findMiddle(head);

    printf("Middle element: %d\n", middle->data);

    return 0;
}

七、循环链表的创建与判断

循环链表是一种特殊的链表,它的最后一个节点指向头节点,形成一个环形结构。创建循环链表需要将最后一个节点的指针指向头节点。判断一个链表是否为循环链表可以通过快慢指针法,如果快指针能够追上慢指针,则链表为循环链表。下面是一个创建和判断循环链表的示例代码:

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

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

int isCircular(Node* head) {
    if (head == NULL)
        return 0;

    Node* slowPtr = head;
    Node* fastPtr = head->next;

    while (fastPtr != NULL && fastPtr->next != NULL) {
        if (slowPtr == fastPtr || slowPtr == fastPtr->next)
            return 1;

        slowPtr = slowPtr->next;
        fastPtr = fastPtr->next->next;
    }

    return 0;
}

int main() {
    Node* head = NULL;

    // 创建循环链表

    int result = isCircular(head);

    if (result)
        printf("The linked list is circular.\n");
    else
        printf("The linked list is not circular.\n");

    return 0;
}

八、头插法与尾插法

链表的插入操作有两种常见的方式:头插法和尾插法。头插法是将新节点插入链表的开头,需要修改头指针;尾插法是将新节点插入链表的末尾,需要修改最后一个节点的指针。下面是一个使用头插法和尾插法插入新节点的示例代码:

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

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

void insertAtHead(Node** head, int value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = *head;
    *head = newNode;
}

void insertAtTail(Node** head, int value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = NULL;

    if (*head == NULL) {
        *head = newNode;
        return;
    }

    Node* current = *head;
    while (current->next != NULL) {
        current = current->next;
    }
    current->next = newNode;
}

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

int main() {
    Node* head = NULL;

    insertAtHead(&head, 3);  // 头插法
    insertAtHead(&head, 2);
    insertAtHead(&head, 1);

    traverse(head);  // 输出:1 2 3

    insertAtTail(&head, 4);  // 尾插法

    traverse(head);  // 输出:1 2 3 4

    return 0;
}

九、释放链表内存

在使用完链表后,需要释放链表所占用的内存,避免内存泄漏。释放链表内存可以通过遍历链表,逐个释放节点的内存。下面是一个释放链表内存的示例代码:

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

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

void freeList(Node** head) {
    Node* current = *head;
    Node* temp;

    while (current != NULL) {
        temp = current;
        current = current->next;
        free(temp);
    }

    *head = NULL;
}

int main() {
    Node* head = NULL;

    // 创建链表

    // 使用链表

    freeList(&head);  // 释放链表内存

    return 0;
}

结语: 通过本篇博客,我们详细介绍了C语言链表和指针的基本概念与用法。九个重要点包括指针的基本概念与使用、链表的基本概念与创建、链表的遍历和插入、链表的删除操作、指针链表的反转、双指针法解决链表问题、循环链表的创建与判断、头插法与尾插法,以及释放链表内存。每个点都配有相应的代码示例,帮助你更好地理解和应用这些概念。希望本篇博客能够帮助你快速掌握C语言链表和指针的使用,提升你的编程技能。祝你编程愉快!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Eric,会点编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值