单链表的构建与查找节点

单链表的构建

  1. 定义节点结构: 在C或C++中,首先你需要定义一个结构体(structclass),用于表示链表中的一个节点。这个结构体通常包含两部分:一个是存储数据的字段,另一个是指向下一个节点的指针

  2. struct Node {
        int data; // 存储数据的字段
       struct Node* next; // 指向下一个节点的指针
    };
  3. 初始化链表: 初始化链表通常意味着创建一个头节点,头节点可以是空的,或者包含一些默认数据。在初始化时,链表的头指针指向这个头节点。

    struct Node* head = NULL; // 如果不使用头结点

    如果使用带头结点的链表,则初始化头结点并让头指针指向它

    struct Node* head = (struct Node*)malloc(sizeof(struct Node));
    head->data = 0; // 可以设置默认值
    head->next = NULL;
  4. 插入节点: 插入节点到链表中可以通过几种方式,最常见的是头插法和尾插法。

    头插法示例

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

    尾插法示例

    void insertAtTail(struct Node** head, int newData) {
        struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
        newNode->data = newData;
        newNode->next = NULL;
    
        if (*head == NULL) {
            *head = newNode;
            return;
        }
    
        struct Node* last = *head;
        while (last->next != NULL)
            last = last->next;
    
        last->next = newNode;
    }
    • 头插法:新节点插入到头结点的后面,成为新的头结点的下一个节点。链表的结点顺序与逻辑次序相反。
    • 尾插法:新节点总是添加到链表的末尾。链表的结点顺序与逻辑次序相同。
  5. 遍历链表: 遍历链表是为了访问每一个节点,通常从头节点开始,直到到达链表的末尾。

    void printList(struct Node* node) {
        while (node != NULL) {
            printf("%d ", node->data);
            node = node->next;
        }
    }
  6. 删除节点: 删除节点可以从链表的任何位置删除,这通常涉及到更新前一个节点的next指针,使其指向被删除节点的下一个节点。

  7. 销毁链表: 当不再需要链表时,应释放所有节点占用的内存,避免内存泄漏。

节点的查找

1. 按值查找

如果你想要查找具有特定值的节点,你可以从链表的头部开始,遍历链表直到找到具有所需值的节点或者到达链表的尾部。这个过程通常需要线性时间,即O(n),其中n是链表中节点的数量。

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

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

// 查找具有特定值的节点
Node* findNodeByValue(Node* head, int value) {
    Node* current = head;
    while (current != NULL) {
        if (current->data == value) {
            return current;
        }
        current = current->next;
    }
    return NULL; // 如果没有找到,返回NULL
}

2. 按位置查找

如果你想按照节点在链表中的位置(例如,第k个节点)进行查找,你可以从链表的头部开始,向前移动k次,到达目标节点或发现链表太短。

Node* findNodeByPosition(Node* head, int position) {
    Node* current = head;
    int count = 0;
    while (current != NULL) {
        if (count == position) {
            return current;
        }
        count++;
        current = current->next;
    }
    return NULL; // 如果没有找到,返回NULL
}

3. 查找中间节点

要查找链表的中间节点,你可以使用“快慢指针”技巧。快指针每次移动两步,慢指针每次移动一步。当快指针到达链表尾部时,慢指针正好位于中间。

Node* findMiddleNode(Node* head) {
    Node* slow = head;
    Node* fast = head;
    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}

4. 查找倒数第k个节点

查找倒数第k个节点通常需要两次遍历,第一次遍历得到链表的长度,第二次遍历可以计算出正数第(length - k + 1)个节点。然而,更高效的方法是使用两个指针,一个领先另一个k步,然后同时移动直到领先指针到达链表尾部。

Node* findKthFromEnd(Node* head, int k) {
    Node* lead = head;
    Node* follow = head;
    
    for (int i = 0; i < k; i++) {
        if (lead == NULL) return NULL; // 如果k大于链表长度,返回NULL
        lead = lead->next;
    }
    
    while (lead != NULL) {
        lead = lead->next;
        follow = follow->next;
    }
    
    return follow;
}

单链表与线性表

单链表作为线性表的一种链式存储结构,支持多种基本运算。以下是基于带头结点的单链表的九种基本运算,它们涵盖了线性表的主要操作:

  1. 初始化单链表 (InitList): 创建一个空的单链表,通常只包含一个头结点,且头结点的next指针指向NULL

  2. 判断单链表是否为空 (ListEmpty): 检查除了头结点外是否还有其他节点,即检查头结点的next是否为NULL

  3. 获取单链表的长度 (ListLength): 从头结点开始遍历,统计非头结点的数量。

  4. 插入节点 (ListInsert): 在指定位置插入一个新节点,可以是在链表的头部、尾部或任意位置。

  5. 删除节点 (ListDelete): 根据位置或值删除链表中的一个节点。

  6. 查找节点 (LocateElem): 按值查找节点,返回节点的位置或直接返回节点本身。

  7. 访问节点 (GetElem): 根据位置访问链表中的一个节点,返回节点的数据。

  8. 修改节点数据 (ListUpdate): 修改链表中指定位置的节点数据。

  9. 输出单链表 (PrintList): 从头结点开始遍历并打印链表中每个节点的数据。

  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

筱姌

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

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

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

打赏作者

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

抵扣说明:

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

余额充值