首页 > 其他分享 >C语言双相循环链表增删查改(带头节点)

C语言双相循环链表增删查改(带头节点)

时间:2024-11-14 22:16:13浏览次数:3  
标签:Node head prev list next 链表 C语言 节点 双相

C语言双相循环链表增删查改(带头节点)

最后一个节点的 next 指针指向第一个节点,第一个节点的 prev 指针指向最后一个节点

定义链表节点

#include <stdio.h>
#include <stdlib.h> // 内存管理,malloc(size_t size)

// 链表节点结构体
typedef struct Node{
    int data;
    struct Node* next;
    struct Node* prev;
}Node;

定义双向循环链表

typedef struct{
    Node* head; // 头节点,虚拟节点
}DouCirLinkedList;

创建新节点

Node* createNewNode(int newData){
    Node* newNode = (Node*)malloc(sizeof(Node));
    if(newNode == NULL){
        printf("Memory allocation failed!\n");
    }
    newNode->data = newData;
    newNode->next = newNode; // 循环链表,初始化指向自己
    newNode->prev = newNode;
    return newNode;
}

创建带头节点空双向循环链表并初始化

DouCirLinkedList* initList(){
    DouCirLinkedList* list = (DouCirLinkedList*)malloc(sizeof(DouCirLinkedList));
    list->head = createNewNode(0); // 创建头节点
    return list;
}

头插节点

void insertAtHead(DouCirLinkedList* list, int newData){ 
    Node* newNode = createNewNode(newData);
    // 新节点的next指针指向原来第一个节点
    newNode->next = list->head->next;
    // 新节点的prev指针指向头节点
    newNode->prev = list->head;
    // 更新原来第一个节点的prev指针指向新节点
    list->head->next->prev = newNode;
    // 更新头节点的next指针指向新节点
    list->head->next = newNode;
}

尾插节点

void insertAtTail(DouCirLinkedList* list, int newData){
    Node* newNode = createNewNode(newData);
    // 找到链表最后一个节点,循环链表很方便
    Node* tail = list->head->prev;
    // 更新新节点的prev指针指向原来最后一个节点
    newNode->prev = tail;
    // 跟新新节点的next指针指向头节点
    newNode->next = list->head;
    // 更新原来最后一个节点的next指针指向新节点
    tail->next = newNode;
    // 更新头节点的prev指针指向新节点
    list->head->prev = newNode;
}

头删节点

void headDelete(DouCirLinkedList* list){
    // 循环链表为空
    if(list->head->next == list->head){ 
        return;
    }
    // 头节点后第一个节点
    Node* temp = list->head->next;
    // 如果链表只有一个节点 
    if(temp->next == temp){
        list->head->next = list->head;
        list->head->prev = list->head;
    }
    else{
        // 更新头节点的next指针指向第二个节点
        list->head->next = temp->next;
        // 更新第二个节点的prev指针指向头节点
        temp->next->prev = list->head;
    }
}

尾删节点

void tailDelete(DouLinkedList* list){
    // 链表为空,只有头节点
    if(list->head->next == list->head){
        return;
    }   
    // 保存获取链表最后一个节点
    Node* tail = list->head->prev;
    // 更新倒数第二个节点的next指针
    tail->prev->next = list->head;
    // 更新第一个节点的prev指针
    list->head->prev = tail->prev;
    // 释放尾节点
    free(tail);
}

查找值为x的节点

Node* searchNode(DouCirLinkedList* list, int x){
    // 从头节点的下一个节点开始遍历
    Node* cur = list->head->next;
    while(cur != list->head){ // 循环直到回到头节点
        if(cur->data == x){
            return cur; // 返回节点
        }
        cur = cur->next;
    }
    return NULL; // 未找到节点,返回NULL
}

修改指定值的节点

int modifyNode(DouCirLinkedList* list, int oldValue, int newValue){
    // 从头节点的下一个节点开始遍历
    Node* cur = list->head->next;
    while(cur != list->head){ // 循环直到回到头节点
        if(cur->data = oldValue){
            cur->data = newValue; // 修改数据
            return 1; // 修改成功返回1
        }
        cur = cur->next;
    }
    return 0; // 没有找到返回0
}

在ptr指针前插入新节点

void insertAtPtr(DouCirLinkedList* list, Node* ptr, int newData){
    if(ptr == NULL || list == NULL){
        return;
    }
    // 创建新节点
    Node* newNode = createNewNode(newData);
    // 更新新节点的next指针
    newNode->next = ptr;
    // 更新新节点的prev指针
    newNode->prev = ptr->prev;
    // 更新ptr前一个节点的next指针指向新节点
    ptr->prev->next = newNode; 
    // 更新ptr指针的prev指针指向新节点
    ptr->prev = newNode; 
}

删除ptr指针指向的节点

void deletePtr(DouCirLinkedList* list, Node* ptr){
    if(ptr == list->head || ptr == NULL){
        return; // 如果ptr为空或是头节点,则直接返回
    }
    // 更新ptr前一个节点的next指针
    ptr->prev->next = ptr->next;
    // 更新ptr后一个节点的prev指针
    ptr->next->prev = ptr->prev;
    free(ptr);
}

打印链表

void printList(DouCirLinkedList* list){
    if(list->head->next == list->head){
        return;
    }
    Node* cur = list->head->next;
    while(cur != list->head){ // 遍历链表直到回到头节点
        printf("%d <-> ", cur->data);
        cur = cur->next;
    }
    printf("\n");
}

销毁链表

void destroyList(DouCirLinkedList* list){
    if(list->head->next == list->head){
        return;
    }
    Node* cur = list->head;
    Node* temp;
    while(cur != list->head){ // 遍历链表直到回到头节点
        temp = cur;
        cur = cur->next;
        free(temp);
    }
    free(list->head);
    free(list);
}

标签:Node,head,prev,list,next,链表,C语言,节点,双相
From: https://blog.csdn.net/paidaxing____/article/details/143782401

相关文章

  • C语言:数组(一维数组,二维数组,数组越界,数组作为函数参量,冒泡排序)
    1、一维数组的创建和初始化1.1、数组的创建数组是相同类型元素的集合•数组中可以存放1个或者多个数据•数组中存放的数据,类型是相同的数组的创建方式:元素类型自定义数组名(常量表达式)比如:intarr[10]doublearr[5]chararr[8+5]错误写法:intarr[n];......
  • C语言中的函数(大白话理解,超详细)
    1、函数是什么?函数就是一种工具,你需要的时候就可以调用他,简化写代码的工作量每个C语言程序至少有一个函数,即主函数main()2、C语言中函数的分类2.1、库函数库函数:是预先编写好的、可供程序员直接使用的函数注意:1、使用库函数必须包括#include对应的头文件(就是""或<>里......
  • C语言期末必练题目——part 9(程序填空)
    6.下面程序的功能是在a数组中查找与x值相同的元素所在位置,请填空。   #include<stdio.h>       void main()        {inta[10],i,x;          printf(“input10integers:”);    for(i=0;i<10;i++)scanf(“%d”,......
  • E45.【C语言】热心网友供题:打印数字金字塔
    目录1.题目题目描述输入说明输出说明输入样例输出样例注意2.自解分析​编辑红色区域的打印橙色区域的打印绿色区域的打印蓝色区域的打印代码不用动脑筋的代码能锻炼思维的代码1.题目题目描述给出10个数,要求以金字塔形式输出,10个数按顺序摆放在金字塔中......
  • 97.【C语言】数据结构之栈
    目录栈1.基本概念2.提炼要点3.概念选择题4.栈的实现栈初始化函数入栈函数出栈函数和栈顶函数栈顶函数栈销毁函数栈基本概念参见王爽老师的《汇编语言第四版》第56和57页节选一部分1.基本概念2.提炼要点1.定义:一种特殊的线性表,其只允许在固定的一端进行......
  • c语言知识点总结-字符串、思维导图
    字面串、字符串变量、字符串的读写、字符串中字符的访问、函数、字符串处理操作、字符串数组总结。文中链接:CSDNhttps://mp.csdn.net/mp_blog/creation/editor/143772084锦黎pro-CSDN博客锦黎pro擅长c语言知识点总结、思维导图,等方面的知识https://blog.csdn.net/jilipro?......
  • 理解C语言之深入理解指针
    目录一、1.内存和地址1.1内存1.2究竟该如何理解编址2.指针变量和地址2.1取地址操作符(&)2.2指针变量和解引⽤操作符(*)2.2.1指针变量2.2.2如何拆解指针类型2.2.3解引⽤操作符2.3指针变量的⼤⼩3.指针变量类型的意义3.1指针的解引⽤3.2指针+-整数3.3v......
  • C语言:函数递归
    #include<stdio.h>intmain(){ printf("haha\n"); main(); return0;}先来看这段代码,这是最简易的一段递归的代码。当我们打印完haha后会main函数调用自己,这样就会使屏幕一直打印haha,但是会停止,这是为什么呢?因为当我们为main函数在栈区开出的内存被不断使用,最后导致栈溢......
  • 单向链表题库2(c++)
    目录前言[1.力扣——LCR123.图书整理I](https://leetcode.cn/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/description/)[2.力扣——LCR024.反转链表](https://leetcode.cn/problems/UHnkqh/submissions/580256040/)[3.力扣LCR141.训练计划III](https://le......
  • C语言之动态内存申请
    动态内存的作用在开发中根据实际需求开辟内存内存申请分类静态内存申请(静态分配)1,在程序编译或运行过程中,按事先规定大小分配内存空间的分配方式,如inta[10];2,必须事先知道所需空间的大小3,分配在栈区或全局变量区,一般以数组形式4,按计划分配特点:在程序运行......