对一个双向链表,从尾部遍历找到第一个值为x的点,将node p插入这个点之前,如果找不到,则插在末尾。使用C语言实现

以下是一个用C语言实现的双向链表(Doubly Linked List)插入操作的代码。该代码从尾部遍历找到第一个值为x的节点,并在其前插入新节点p,或者在未找到时将其插入链表末尾。

c 复制代码
 #include <stdio.h>
#include <stdlib.h>

// 定义双向链表节点结构
typedef struct DoublyListNode {
    int val;
    struct DoublyListNode *prev;
    struct DoublyListNode *next;
} DoublyListNode;

// 创建新节点
DoublyListNode* createNode(int val) {
    DoublyListNode *newNode = (DoublyListNode*)malloc(sizeof(DoublyListNode));
    newNode->val = val;
    newNode->prev = NULL;
    newNode->next = NULL;
    return newNode;
}

// 在双向链表中插入新节点
DoublyListNode* insertBeforeXOrAppend(DoublyListNode *head, int x, int pVal) {
    if (head == NULL) {
        // 如果链表为空,直接创建新节点并返回
        return createNode(pVal);
    }

    DoublyListNode *curr = head;
    // 从头部开始遍历直到尾部
    while (curr->next != NULL) {
        curr = curr->next;
    }

    // 从尾部开始向前遍历找到第一个值为x的节点
    while (curr != NULL && curr->val != x) {
        curr = curr->prev;
    }

    // 如果找到了值为x的节点
    if (curr != NULL) {
        DoublyListNode *newNode = createNode(pVal);
        newNode->next = curr->next;
        newNode->prev = curr;
        if (curr->next != NULL) {
            curr->next->prev = newNode;
        }
        curr->next = newNode;
    } else {
        // 如果没有找到值为x的节点,则插入到末尾
        DoublyListNode *newNode = createNode(pVal);
        newNode->prev = curr; // curr此时为链表的最后一个节点或NULL(当链表为空时,但这种情况已在开头处理)
        if (curr != NULL) {
            curr->next = newNode;
        }
        // 如果链表原本为空,则newNode既是头节点也是尾节点,无需额外设置head
        // 否则,head不变,因为新节点是插入到末尾的,不影响头节点
    }

    // 注意:此函数不改变头节点的地址,因此无需返回新的头节点(除非链表原本为空)
    // 但为了保持接口的一致性,这里仍然返回头节点(尽管它可能没变)
    return head; // 在这个特定实现中,头节点要么不变,要么在函数外部已经处理(如链表为空时)
}

// 打印双向链表
void printList(DoublyListNode *head) {
    DoublyListNode *curr = head;
    while (curr != NULL) {
        printf("%d ", curr->val);
        curr = curr->next;
    }
    printf("\n");
}

// 释放双向链表内存
void freeList(DoublyListNode *head) {
    DoublyListNode *curr = head;
    while (curr != NULL) {
        DoublyListNode *next = curr->next;
        free(curr);
        curr = next;
    }
}

int main() {
    // 创建双向链表 1 <-> 2 <-> 3 <-> 4
    DoublyListNode *head = createNode(1);
    head->next = createNode(2);
    head->next->prev = head;
    head->next->next = createNode(3);
    head->next->next->prev = head->next;
    head->next->next->next = createNode(4);
    head->next->next->next->prev = head->next->next;

    int x = 3;
    int pVal = 99;

    // 插入新节点
    insertBeforeXOrAppend(head, x, pVal);

    // 打印双向链表
    printList(head);

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

    return 0;
}

注意:

  1. 上述代码中的insertBeforeXOrAppend函数实际上不需要返回新的头节点地址,因为插入操作要么在链表末尾进行(不改变头节点),要么在链表中间进行(同样不改变头节点)。但是,为了保持函数接口的一致性(比如,如果以后需要修改这个函数以处理链表为空时的特殊情况,并返回新的头节点),这里仍然返回了头节点。在实际应用中,如果确定头节点不会改变,可以省略返回值。

  2. 在main函数中,我们创建了一个简单的双向链表,并调用了insertBeforeXOrAppend函数来插入新节点。然后,我们打印链表并释放其内存。

带头链表:在链表的首部增加一个不存储有效数据的头节点。头节点的作用主要是简化链表的操作,特别是在处理空表时,无论表是否为空,头指针都指向头节点,从而使得空表和非空表的操作一致。

带头单向非循环链表:结构简单,但一般不会单独用来存储数据,而是作为其他数据结构的子结构,如哈希桶、图的邻接表等。

带头双向循环链表:结构最复杂,但一般用在单独存储数据的场景。实际中使用的链表数据结构,很多都是带头双向循环链表。虽然结构复杂,但使用代码实现后会发现,这种结构能带来很多优势。

相关推荐
mit6.82441 分钟前
[Broken IOS] 配置&CLI | 终端用户界面TUI
c语言·ios·cocoa
草莓熊Lotso43 分钟前
【LeetCode刷题指南】--单值二叉树,相同的树
c语言·数据结构·算法·leetcode·刷题
Asu52021 小时前
链表反转中最常用的方法————三指针法
java·数据结构·学习·链表
yunnanwang2 小时前
鹏哥C语言_85_结构体下(结构体传参)
c语言·开发语言
闪电麦坤952 小时前
数据结构:在链表中查找(Searching in a Linked List)
数据结构·链表
给老吕螺丝2 小时前
C 语言作用域与存储期深度解析:空间与时间的双重维度
c语言·开发语言·经验分享·笔记
ankleless4 小时前
C语言(02)——标准库函数大全(持续更新)
c语言·开发语言·算法·标准库函数·零基础自学
玖剹4 小时前
Linux文件系统:从内核到缓冲区的奥秘
linux·c语言·c++·笔记·ubuntu
范纹杉想快点毕业4 小时前
基于 C 语言视角:流程图中分支与循环结构的深度解析
c语言·stm32·单片机·设计模式·架构·流程图·uml
l1t4 小时前
修改DeepSeek翻译得不对的V语言字符串文本排序程序
c语言·开发语言·python·v语言