数据结构-链表-单向链表-02.链表代码的研究-无头链表

1. 定义节点结构体: 链表中的每个节点都包含一个数据域和一个指向下一个节点的指针。可以通过结构体来定义节点。

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

// 定义节点结构体
typedef struct Node {
    int data;           // 数据域
    struct Node *next;  // 指针域,指向下一个节点
} Node;

这两种头插法存在细微的细节:

头插法1:

void headInsert(Node **head, int data) {
    // 创建新节点并分配内存空间
    Node *newNode = (Node *)malloc(sizeof(Node));
    newNode->data = data;
    // 将新节点的指针指向当前头节点
    newNode->next = *head;
    // 更新头节点指针为新节点
    *head = newNode;
}

头插法2:

Node *insertNodeAtBeginning(Node *head, int newData) {
    // 创建新节点并分配内存空间
    Node *newNode = (Node *)malloc(sizeof(Node));
    newNode->data = newData;
    // 将新节点的指针指向当前头节点
    newNode->next = head;
    // 更新头节点指针为新节点
    head = newNode;
    return head;
}

主要区别在于返回值和参数的不同:

  • 头插法 1 接受一个指向指针的指针作为参数,它直接修改了头指针本身,因此不需要返回值。

  • 头插法 2 接受当前链表的头指针作为参数,并返回更新后的头指针。因为它不直接修改头指针本身,而是返回更新后的头指针。

以下是尾插法

尾插法1:

void tailInsert(Node **head, int data) {
    // 创建新节点并分配内存空间
    Node *newNode = (Node *)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = NULL; // 将新节点的下一个节点指针设为 NULL,表示它是链表的最后一个节点

    // 如果链表为空,直接将新节点设为头节点
    if (*head == NULL) {
        *head = newNode;
        return;
    }

    // 找到链表的最后一个节点
    Node *current = *head;
    while (current->next != NULL) {
        current = current->next;
    }

    // 将新节点连接到链表的最后一个节点之后
    current->next = newNode;
}

尾插法2:

Node *tailInsert(Node *head, int newData) {
    // 创建新节点并分配内存空间
    Node *newNode = (Node *)malloc(sizeof(Node));
    newNode->data = newData;
    newNode->next = NULL; // 新节点将成为链表的最后一个节点,因此其下一个节点指针设为 NULL

    // 如果链表为空,直接将新节点设为头节点并返回
    if (head == NULL) {
        return newNode;
    }

    // 找到链表的最后一个节点
    Node *current = head;
    while (current->next != NULL) {
        current = current->next;
    }

    // 将新节点连接到链表的最后一个节点之后
    current->next = newNode;

    // 返回原头节点
    return head;
}
这个函数与头插法相比,主要区别在于返回值的处理。在尾插法中,需要保持原头节点不变,因此返回原头节点的指针。然后,将新节点插入到链表的末尾,最后返回原头节点的指针。

在使用上,头插法 1 更适合于不需要返回头指针的场景,而头插法 2 更适合于需要返回头指针的场景。通常情况下,两者的功能是相同的,只是接口设计上稍有不同。

单向链表的基本操作主要有以下5个功能,增(头插法,尾插法),删(头删法,尾删法,和删一个节点),改,查,销毁,所以,以下将会针对两种形式的无头链表进行删,改,查和销毁。

头删法1:

void headDelete(Node **head) {
    // 如果链表为空,直接返回
    if (*head == NULL) {
        printf("List is empty.\n");
        return;
    }

    // 保存头节点到临时变量
    Node *temp = *head;
    // 更新头节点指针为原头节点的下一个节点
    *head = (*head)->next;
    // 释放临时变量指向的节点的内存空间
    free(temp);
}

尾删法1:

void tailDelete(Node **head) {
    // 如果链表为空,直接返回
    if (*head == NULL) {
        printf("List is empty.\n");
        return;
    }

    // 如果链表只有一个节点,直接释放头节点,并将头指针置为空
    if ((*head)->next == NULL) {
        free(*head);
        *head = NULL;
        return;
    }

    // 找到倒数第二个节点
    Node *prev = *head;
    while (prev->next->next != NULL) {
        prev = prev->next;
    }

    // 保存最后一个节点到临时变量
    Node *temp = prev->next;
    // 倒数第二个节点的下一个节点指针设为 NULL
    prev->next = NULL;
    // 释放临时变量指向的节点的内存空间
    free(temp);
}

删一个1:

void deleteNodeByValue(Node **head, int data) {
    // 如果链表为空,直接返回
    if (*head == NULL) {
        printf("List is empty.\n");
        return;
    }

    // 如果头节点是要删除的节点
    if ((*head)->data == data) {
        Node *temp = *head;
        *head = (*head)->next;
        free(temp);
        return;
    }

    // 寻找要删除节点的前一个节点
    Node *prev = *head;
    while (prev->next != NULL && prev->next->data != data) {
        prev = prev->next;
    }

    // 如果未找到要删除的节点,则返回
    if (prev->next == NULL) {
        printf("Node with data %d not found.\n", data);
        return;
    }

    // 找到要删除的节点,删除它
    Node *temp = prev->next;
    prev->next = temp->next;
    free(temp);
}

头删法2:

Node *headDelete(Node *head) {
    // 如果链表为空,直接返回
    if (head == NULL) {
        printf("List is empty.\n");
        return NULL;
    }

    // 保存头节点的下一个节点到临时变量
    Node *temp = head->next;
    // 释放头节点的内存空间
    free(head);
    // 返回新的头节点
    return temp;
}

尾删法2:

Node *tailDelete(Node *head) {
    // 如果链表为空,直接返回
    if (head == NULL) {
        printf("List is empty.\n");
        return NULL;
    }

    // 如果链表只有一个节点,直接释放头节点,并返回 NULL
    if (head->next == NULL) {
        free(head);
        return NULL;
    }

    // 找到倒数第二个节点
    Node *prev = head;
    while (prev->next->next != NULL) {
        prev = prev->next;
    }

    // 保存最后一个节点到临时变量
    Node *temp = prev->next;
    // 倒数第二个节点的下一个节点指针设为 NULL
    prev->next = NULL;
    // 释放最后一个节点的内存空间
    free(temp);
    // 返回头节点
    return head;
}

删一个2:

Node *deleteNodeByValue(Node *head, int data) {
    // 如果链表为空,直接返回
    if (head == NULL) {
        printf("List is empty.\n");
        return NULL;
    }

    // 如果头节点是要删除的节点
    if (head->data == data) {
        Node *temp = head;
        head = head->next;
        free(temp);
        return head;
    }

    // 寻找要删除节点的前一个节点
    Node *prev = head;
    while (prev->next != NULL && prev->next->data != data) {
        prev = prev->next;
    }

    // 如果未找到要删除的节点,则返回
    if (prev->next == NULL) {
        printf("Node with data %d not found.\n", data);
        return head;
    }

    // 找到要删除的节点,删除它
    Node *temp = prev->next;
    prev->next = temp->next;
    free(temp);
    return head;
}

改1:

void modifyNode(Node **head, int oldData, int newData) {
    // 如果链表为空,直接返回
    if (*head == NULL) {
        printf("List is empty.\n");
        return;
    }

    // 查找要修改的节点
    Node *current = *head;
    while (current != NULL) {
        if (current->data == oldData) {
            current->data = newData;
            return;
        }
        current = current->next;
    }

    printf("Node with data %d not found.\n", oldData);
}

查1:

Node *findNode(Node *head, int data) {
     Node *current = *head;
    while (current != NULL) {
        if (current->data == data) {
            return current;
        }
        current = current->next;
    }
    return NULL;
}

销毁1:

void destroyList(Node **head) {
    // 释放链表的所有节点
    while (*head != NULL) {
        Node *temp = *head;
        *head = (*head)->next;
        free(temp);
    }
}

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值