六、数据结构——双向循环链表在数据结构中的基本操作详解:创建、插入(头插法、尾插法、任意点插法)、删除(头删法、尾删法、任意位置删法)、查询(按值查下标、按下标查值)、遍历链表和清空链表

详细介绍C语言中双向循环链表在数据结构中的实现和基本操作

目录

一、什么是双向循环链表
二、双向循环链表的特点
三、双向循环链表的优缺点
四、双向循环链表的应用场景
五、双向循环链表的常见操作
1、双向循环链表的定义和结构
2、创建双向循环链表头
3、判断链表是否为空
4、在双向循环链表中插入节点
5、从双向循环链表中删除节点
6、查找链表的元素或元素的下标
7、修改链表的元素
8、获取链表的长度
9、遍历双向循环链表
10、释放双向循环链表的内存
11、完整代码

数据结构是计算机科学中的核心概念之一。在开发和设计算法时,选择合适的数据结构对于程序的性能和可读性至关重要。双向循环链表是一种常用的数据结构,它允许在链表中进行前后遍历,并且可以很方便地插入和删除节点。本文将详细介绍双向循环链表的概念、特点以及常见操作的实现方法。

一、什么是双向循环链表?

双向循环链表是一种链表数据结构,它的节点包含两个指针:一个指向前一个节点,一个指向后一个节点。与单向链表不同的是,双向循环链表的最后一个节点的后继指针指向第一个节点,而第一个节点的前驱指针指向最后一个节点,形成一个循环的闭环。

二、双向循环链表的特点

双向遍历:由于每个节点都有前驱和后继指针,可以从任意一个节点出发,向前或向后遍历整个链表。
循环性质:最后一个节点的后继指针指向第一个节点,第一个节点的前驱指针指向最后一个节点,形成一个循环。
灵活插入和删除:相比于单向链表,双向循环链表的插入和删除操作更为灵活方便,不需要遍历整个链表来寻找特定位置。

三、双向循环链表的优缺点

优点:灵活插入和删除节点、双向遍历链表、循环性质使得某些问题更容易解决。
缺点:相对于单向链表,每个节点需要额外存储两个指针,占用更多的内存空间;修改和查询比较麻烦

四、双向循环链表的应用场景

缓存淘汰算法:例如LRU缓存算法中,使用双向循环链表来维护最近访问的数据。
图的遍历:在图的深度优先搜索和广度优先搜索中,可以使用双向循环链表作为辅助数据结构来存储已访问的节点。

五、双向循环链表的常见操作

1、双向循环链表的定义和结构

// 链表节点结构体
typedef struct Node {
    typData data;// 节点数据
    int tail;//记录节点数
    struct Node *prev;//指向上一个节点的指针
    struct Node *next;//指向下一个节点的指针
} Linklist, *Plinklist;

2、创建双向循环链表头

在这里插入图片描述

// 创建链表
Plinklist createLinkedList(Plinklist *list){
    (*list) = (Plinklist)malloc(sizeof(Linklist));//为表头申请空间
    if((*list) == NULL){
        perror("createLinkedList list malloc");
    }   
    (*list)->prev = *list;//头节点的上一个节点还是指向头节点
    (*list)->next = *list;//头节点的下一个节点还是指向头节点
    (*list)->tail = 1;//记录节点数,带头节点已经存在
    return *list;
}

3、判断链表是否为空

// 判断链表是否为空
int isEmpty(Plinklist list){
    if(list->next == list || list->tail == 0){ 
        //puts("表是空的!");
        return 1;//真空
    }else{
        return 0;//非空
    }   
}

4、在双向循环链表中插入节点

①头插法:在带头节点的后面插入
1、只有一个带头结点
在这里插入图片描述
2、不只带头结点
在这里插入图片描述

// 在链表头部插入元素
void insertAtHead(Plinklist list, typData value){
    if(list == NULL){
        puts("insert head arg err");
        return ;
    }

    Plinklist newNode = (Plinklist)malloc(sizeof(Linklist));
    if(newNode == NULL){
        perror("insert head newNode malloc");//头插入内存分配失败
        return ;
    }
    newNode->data = value;//设置新节点的数据值

    if(list->next == list && list->prev == list){
        newNode->next = list;
        newNode->prev = list;
        list->prev = newNode;
        list->next = newNode;
    }else{
        newNode->next = list->next;
        newNode->prev = list;
        list->next->prev = newNode;
        list->next = newNode;
    }

    list->tail++;//链表长度加一

}

②尾插法
在这里插入图片描述

// 在链表尾部插入元素
void insertAtTail(Plinklist list, typData value){
    if(list == NULL){
        puts("insert tail arg err");
        return ;
    }

    Plinklist newNode = (Plinklist)malloc(sizeof(Linklist));
    if(newNode == NULL){
        perror("insert tail newNode malloc");
        return ;
    }
    newNode->data = value;// 设置新节点的数据值
    newNode->next = list;// 新节点的后继节点指向NULL

    Plinklist current_tail = list;// 重新定义一个新指针指向头节点
    while(current_tail->next != list){
        current_tail = current_tail->next;// 遍历找到链表的尾节点
    }

    newNode->prev = current_tail;// 新节点的前驱节点指向尾节点
    list->prev = newNode;
    current_tail->next = newNode;// 尾节点的后继节点指向新节点

    list->tail++;// 节点数加一

}

③在任意位置插入法
在这里插入图片描述

// 在指定位置插入元素
void insertAtPosition(Plinklist list, int position, typData value){
    if(list ==NULL){
        puts("insert position arg err");
        return ;
    }

    if(position < 0 || position > (list->tail)){// 检查输入的position下标是否存在
        puts("无效位置!");
        return ;
    }

    Plinklist newNode = (Plinklist)malloc(sizeof(Linklist));//创建一个要插入的新节点
    newNode->data = value;//设置新节点的数据值
    Plinklist current = list;//重新定义一个新指针指向头节点
    int count = 0;//定义一个计数变量
    while(current->next != list && count < position){
        current = current->next;// 找到要插入位置的前一个节点
        count++;
    }

    newNode->next = current->next;// 新节点的后继指向要原删除节点的前一节点的下一个节点
    newNode->prev = current;// 新节点的前驱指向新节点的前一节点
    if (current->next != list) {
        current->next->prev = newNode;// 更新原来节点和新节点的连接
    }
    current->next = newNode;// 将新界嗲连接到原节点之后

    list->tail++;
}

5、从双向循环链表中删除节点

①删除头节点
在这里插入图片描述

// 删除头节点
void deleteHead(Plinklist list){
    if(list ==NULL){
        puts("dalete head arg err");
        return ;
    }

    if(isEmpty(list)){
        puts("表是空的!");
        return ;
    }

    Plinklist deleteHead = list->next;// 定义一个新的删除指针指向头节点的下一个节点
    list->next = deleteHead->next;// 头节点的后继更新为要删除节点的后一个后一个节点(也
可以是list>next = list->next->next)
    if (deleteHead->next != list) {
        deleteHead->next->prev = list;// 更新头节点和新节点的连接
    }else{
        list->next = list;
        list->prev = list;
    }

    free(deleteHead);//释放删除节点的内存
    list->tail--;// 节点数减一
}

②删除尾节点
在这里插入图片描述

// 删除尾节点
void deleteTail(Plinklist list){
    if(list ==NULL){
        puts("dalete tail arg err");
        return ;
    }

    if(isEmpty(list)){
        puts("表是空的!");
        return ;
    }

    Plinklist current = list;
    while(current->next != list){
        current = current->next; 找到尾节点
    }
    //Plinklist deleteTail = current;
    current->prev->next = list;// 要删除节点的上一个节点的后继直接连接NULL,断开要删除>节点和NULL的连接
    list->prev = current->prev;
    free(current);

    list->tail--;// 节点数减一
}

③删除任意节点
在这里插入图片描述

// 删除指定位置的节点
void deleteAtPosition(Plinklist list, int position){
    if (isEmpty(list)) {
        printf("链表为空,删不了,根本删不了\n");
        return ;
    }

    Plinklist current = list;  // 从头节点开始遍历链表,找到要删除节点的前一个节点
    int count = 0;
    while (current->next != list && count < position) {
        current = current->next;// 不断更新current指针
        count++;
    }

    if (current->next == list || position < 0) {// 检查删除位置的有效性
        printf("无效的删除位置\n");
        return ;
    }

    Plinklist deletePosition = current->next;//定义新的指针记录要删除节点的上一个节点
    current->next = deletePosition->next;// 要删除节点的上一个节点的后继连接到要删除节>点的后一个节点,断开要删除节点的和要删除节点的上一个节点的后继

    if (deletePosition->next != list) {
        deletePosition->next->prev = current;//更新前后节点的连接
    }


    free(deletePosition);//释放删除节点的内存
    list->tail--;//节点数减一
    if (isEmpty(list)) {
        printf("链表为空,删不了了,根本删不了了\n");
        return ;
    }
}

6、查找链表的元素或元素的下标

①按值查找节点的下标位置

// 按值查找节点的位置
int findPositionByValue(Plinklist list, typData value){
    if(list ==NULL){
        puts("findValue Position arg err");
        return -1;
    }

    if(isEmpty(list)){
        puts("表是空的!");
        return 1;
    }

    Plinklist current = list->next;
    int position = 0;//定义下标从0开始
    while (current != list) {
        if (current->data == value) {
            return position;  // 找到节点的数据值等于目标值,返回节点的下标
        }
        current = current->next;
        position++;
    }
    printf("没有该值!");
    return -1;  // 未找到目标值,返回false
}

②// 按下标查找节点的值

int findValueByPosition(Plinklist list, int position){
    if(list ==NULL){
        puts("findPosition Value arg err");
        return -1;
    }

    if(isEmpty(list)){
        puts("表是空的!");
        return 1;
    }

    Plinklist current = list->next;  // 从第一个节点开始遍历链表
    int count = 0;
    while (current != list && count < position) {
        current = current->next;
        count++;
    }

    if (current == list || position < 0 || position > (list->tail)) {// 检查下标的有效>性
        printf("无效的下标\n");
        return -1;
    }

    return current->data;  // 返回找到的节点的数据值
}

7、修改链表的元素

①修改指定下标位置的节点值

// 修改指定位置的节点值
void modifyByPosition(Plinklist list, int position, typData value){
    if(list ==NULL){
        puts("modifyPosition Value arg err");
        return ;
    }

    if (isEmpty(list)) {
        printf("链表为空,无法修改元素\n");
        return ;
    }

    Plinklist current = list->next;  // 从第一个节点开始遍历链表
    int count = 0;
    while (current != list && count < position) {
        current = current->next;
        count++;
    }

    if (current == NULL || position < 0 || position > list->tail) {
        printf("无效的下标\n");
        return ;
    }

    current->data = value;  // 修改节点的数据值
}

②修改指定值的节点值

// 修改指定值的节点值
void modifyValue(Plinklist list, typData oldValue, typData newValue){
    if(list ==NULL){
        puts("modifyValue Value arg err");
        return ;
    }
    if (isEmpty(list)) {
        printf("链表为空,无法修改节点值\n");
        return ;
    }

    Plinklist current = list->next;  // 从第一个节点开始遍历链表
    while (current != list) {
        if (current->data == oldValue) {
            current->data = newValue;  // 找到节点的数据值等于旧值,更新节点的数据值为新值
            return ;
        }
        current = current->next;
    }

    printf("未找到目标值\n");
}

8、获取链表的长度

// 获取链表长度
int getLength(Plinklist list){
    if(isEmpty(list)){
        puts("链表为空!");
        return 0;
    }
    return (list->tail) - 1;
    //return list->tail;

}

9、遍历双向循环链表

①向前遍历(从带头结点的下一个节点开始遍历到尾节点)

//向前遍历链表并打印节点值(从头节点遍历到尾节点)
void next_traverse(Plinklist list){
    if(list == NULL){
        puts("next_traverse arg err");
        return ;
    }
    if(isEmpty(list)){
        puts("链表为空!");
        return ;
    }

    Plinklist current = list->next;

    while (current != list) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}

②向后遍历(从尾节点遍历到带头结点的下一个节点)

//向后遍历链表并打印节点值(从尾节点遍历到头节点)
void prev_traverse(Plinklist list){
    if(list == NULL){
        puts("prev_traverse arg err");
        return ;
    }
    if(isEmpty(list)){
        puts("链表为空!");
        return ;
    }
    Plinklist current_tail = list;
    while(current_tail->next != list){
        current_tail = current_tail->next;// 找到尾节点
    }
    Plinklist current = current_tail;
    while(current != list){
        printf("%d ",current->data);// 打印节点值
        current = current->prev;
    }
    printf("\n");
}

10、释放双向循环链表的内存

同样我们调用删头函数或者删尾函数

// 清空链表
void clearList(Plinklist list){
    while(list->next != list){
        deleteHead(list);//调用删除头节点函数,实现不断的删除头节点
    }
    printf("表已被清空!\n");
    return ;
}


11、完整代码

同样分三个文件来执行:①接口文件dlinklist.h ②接口实现文件dlinklist.c ③函数调用文件dlinklist_main.c

①接口文件dlinklist.h

#ifndef _BLINKLIST_H_
#define _BLINKLIST_H_
#include <stdio.h>
#include <stdlib.h>
typedef int typData;

// 链表节点结构体
typedef struct Node {
    typData data;// 节点数据
    int tail;//记录节点数
    struct Node *prev;//指向下一个节点的指针
    struct Node *next;//指向下一个节点的指针
} Linklist, *Plinklist;

// 创建链表
Plinklist createLinkedList(Plinklist *list);

// 判断链表是否为空
int isEmpty(Plinklist list);

// 在链表头部插入元素
void insertAtHead(Plinklist list, typData value);

// 在链表尾部插入元素
void insertAtTail(Plinklist list, typData value);

// 在指定位置插入元素
void insertAtPosition(Plinklist list, int position, typData value);

// 删除头节点
void deleteHead(Plinklist list);

// 删除尾节点
void deleteTail(Plinklist list);

// 删除指定位置的节点
void deleteAtPosition(Plinklist list, int position);

// 按值查找节点的位置
int findPositionByValue(Plinklist list, typData value);

// 按下标查找节点的值
int findValueByPosition(Plinklist list, int position);

// 修改指定位置的节点值
void modifyByPosition(Plinklist list, int position, typData value);

// 修改指定值的节点值
void modifyValue(Plinklist list, typData oidValue, typData newValue);

// 获取链表长度
int getLength(Plinklist list);

// 向前遍历链表并打印节点值
void prev_traverse(Plinklist list);

// 向后遍历链表并打印节点值
void next_traverse(Plinklist list);

// 清空链表
void clearList(Plinklist list);

#endif

②接口实现文件dlinklist.c

#include "dlinklist.h"
// 创建链表
Plinklist createLinkedList(Plinklist *list){
    (*list) = (Plinklist)malloc(sizeof(Linklist));//为表头申请空间
    if((*list) == NULL){
        perror("createLinkedList list malloc");
    }
    (*list)->prev = *list;//头节点的上一个节点还是指向头节点
    (*list)->next = *list;//头节点的下一个节点还是指向头节点
    (*list)->tail = 1;//记录节点数
    return *list;
}

// 判断链表是否为空
int isEmpty(Plinklist list){
    if(list->next == list || list->tail == 0){
        //puts("表是空的!");
        return 1;//真空
    }else{
        return 0;//非空
    }
}


// 在链表头部插入元素
void insertAtHead(Plinklist list, typData value){
    if(list == NULL){
        puts("insert head arg err");
        return ;
    }

    Plinklist newNode = (Plinklist)malloc(sizeof(Linklist));
    if(newNode == NULL){
        perror("insert head newNode malloc");//头插入内存分配失败
        return ;
    }
    newNode->data = value;//设置新节点的数据值

    if(list->next == list && list->prev == list){
        newNode->next = list;
        newNode->prev = list;
        list->prev = newNode;
        list->next = newNode;
    }else{
        newNode->next = list->next;
        newNode->prev = list;
        list->next->prev = newNode;
        list->next = newNode;
    }

    list->tail++;//链表长度加一

}


// 在链表尾部插入元素
void insertAtTail(Plinklist list, typData value){
    if(list == NULL){
        puts("insert tail arg err");
        return ;
    }

    Plinklist newNode = (Plinklist)malloc(sizeof(Linklist));
    if(newNode == NULL){
        perror("insert tail newNode malloc");
        return ;
    }
    newNode->data = value;// 设置新节点的数据值
    newNode->next = list;// 新节点的后继节点指向NULL

    Plinklist current_tail = list;// 重新定义一个新指针指向头节点
    while(current_tail->next != list){
        current_tail = current_tail->next;// 遍历找到链表的尾节点
    }

    newNode->prev = current_tail;// 新节点的前驱节点指向尾节点
    list->prev = newNode;
    current_tail->next = newNode;// 尾节点的后继节点指向新节点

    list->tail++;// 节点数加一

}

// 在指定位置插入元素
void insertAtPosition(Plinklist list, int position, typData value){
    if(list ==NULL){
        puts("insert position arg err");
        return ;
    }

    if(position < 0 || position > (list->tail)){// 检查输入的position下标是否存在
        puts("无效位置!");
        return ;
    }

    Plinklist newNode = (Plinklist)malloc(sizeof(Linklist));//创建一个要插入的新节点
    newNode->data = value;//设置新节点的数据值
    Plinklist current = list;//重新定义一个新指针指向头节点
    int count = 0;//定义一个计数变量
    while(current->next != list && count < position){
        current = current->next;// 找到要插入位置的前一个节点
        count++;
    }

    newNode->next = current->next;// 新节点的后继指向要原删除节点的前一节点的下一个节点
    newNode->prev = current;// 新节点的前驱指向新节点的前一节点
    if (current->next != list) {
        current->next->prev = newNode;// 更新原来节点和新节点的连接
    }
    current->next = newNode;// 将新界嗲连接到原节点之后

    list->tail++;
}


// 删除头节点
void deleteHead(Plinklist list){
    if(list ==NULL){
        puts("dalete head arg err");
        return ;
    }

    if(isEmpty(list)){
        puts("表是空的!");
        return ;
    }

    Plinklist deleteHead = list->next;// 定义一个新的删除指针指向头节点的下一个节点
    list->next = deleteHead->next;// 头节点的后继更新为要删除节点的后一个后一个节点(也可以是list>next = list->next->next)
    if (deleteHead->next != list) {
        deleteHead->next->prev = list;// 更新头节点和新节点的连接
    }else{
        list->next = list;
        list->prev = list;
    }

    free(deleteHead);//释放删除节点的内存
    list->tail--;// 节点数减一
}


// 删除尾节点
void deleteTail(Plinklist list){
    if(list ==NULL){
        puts("dalete tail arg err");
        return ;
    }

    if(isEmpty(list)){
        puts("表是空的!");
        return ;
    }

    Plinklist current = list;
    while(current->next != list){
        current = current->next; 找到尾节点
    }
    //Plinklist deleteTail = current;
    current->prev->next = list;// 要删除节点的上一个节点的后继直接连接NULL,断开要删除节点和NULL的连接
    list->prev = current->prev;
    free(current);

    list->tail--;// 节点数减一
}

// 删除指定位置的节点
void deleteAtPosition(Plinklist list, int position){
    if (isEmpty(list)) {
        printf("链表为空,删不了,根本删不了\n");
        return ;
    }

    Plinklist current = list;  // 从头节点开始遍历链表,找到要删除节点的前一个节点
    int count = 0;
    while (current->next != list && count < position) {
        current = current->next;// 不断更新current指针
        count++;
    }

    if (current->next == list || position < 0) {// 检查删除位置的有效性
        printf("无效的删除位置\n");
        return ;
    }

    Plinklist deletePosition = current->next;//定义新的指针记录要删除节点的上一个节点
    current->next = deletePosition->next;// 要删除节点的上一个节点的后继连接到要删除节点的后一个节点,断开要删除节点的和要删除节点的上一个节
点的后继

    if (deletePosition->next != list) {
        deletePosition->next->prev = current;//更新前后节点的连接
    }


    free(deletePosition);//释放删除节点的内存
    list->tail--;//节点数减一
    if (isEmpty(list)) {
        printf("链表为空,删不了了,根本删不了了\n");
        return ;
    }
}


// 按值查找节点的位置
int findPositionByValue(Plinklist list, typData value){
    if(list ==NULL){
        puts("findValue Position arg err");
        return -1;
    }

    if(isEmpty(list)){
        puts("表是空的!");
        return 1;
    }

    Plinklist current = list->next;
    int position = 0;//定义下标从0开始
    while (current != list) {
        if (current->data == value) {
            return position;  // 找到节点的数据值等于目标值,返回节点的下标
        }
        current = current->next;
        position++;
    }
    printf("没有该值!");
    return -1;  // 未找到目标值,返回false
}


// 按下标查找节点的值
int findValueByPosition(Plinklist list, int position){
    if(list ==NULL){
        puts("findPosition Value arg err");
        return -1;
    }

    if(isEmpty(list)){
        puts("表是空的!");
        return 1;
    }

    Plinklist current = list->next;  // 从第一个节点开始遍历链表
    int count = 0;
    while (current != list && count < position) {
        current = current->next;
        count++;
    }

    if (current == list || position < 0 || position > (list->tail)) {// 检查下标的有效性
        printf("无效的下标\n");
        return -1;
    }

    return current->data;  // 返回找到的节点的数据值
}


// 修改指定位置的节点值
void modifyByPosition(Plinklist list, int position, typData value){
    if(list ==NULL){
        puts("modifyPosition Value arg err");
        return ;
    }

    if (isEmpty(list)) {
        printf("链表为空,无法修改元素\n");
        return ;
    }

    Plinklist current = list->next;  // 从第一个节点开始遍历链表
    int count = 0;
    while (current != list && count < position) {
        current = current->next;
        count++;
    }

    if (current == NULL || position < 0 || position > list->tail) {
        printf("无效的下标\n");
        return ;
    }

    current->data = value;  // 修改节点的数据值
}


// 修改指定值的节点值
void modifyValue(Plinklist list, typData oldValue, typData newValue){
    if(list ==NULL){
        puts("modifyValue Value arg err");
        return ;
    }
    if (isEmpty(list)) {
        printf("链表为空,无法修改节点值\n");
        return ;
    }

    Plinklist current = list->next;  // 从第一个节点开始遍历链表
    while (current != list) {
        if (current->data == oldValue) {
            current->data = newValue;  // 找到节点的数据值等于旧值,更新节点的数据值为新值
            return ;
        }
        current = current->next;
    }

    printf("未找到目标值\n");
}


// 获取链表长度
int getLength(Plinklist list){
    if(isEmpty(list)){
        puts("链表为空!");
        return 0;
    }
    return (list->tail) - 1;
    //return list->tail;

}


//向后遍历链表并打印节点值(从尾节点遍历到头节点)
void prev_traverse(Plinklist list){
    if(list == NULL){
        puts("prev_traverse arg err");
        return ;
    }
    if(isEmpty(list)){
        puts("链表为空!");
        return ;
    }
    Plinklist current_tail = list;

    while (current != list) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}

// 清空链表
void clearList(Plinklist list){
    while(list->next != list){
        deleteHead(list);//调用删除头节点函数,实现不断的删除头节点
    }
    printf("表已被清空!\n");
    return ;
}

③函数调用文件dlinklist_main.c

int main() {
    Plinklist list;
    createLinkedList(&list);

    int choice, value, position, oldValue, newValue;

    while (1) {
        printf("\n*****************************链表操作菜单*****************************\n");
        printf("1. 在头部插入元素           2. 在尾部插入元素           3. 在任意位置插入元素\n");
        printf("4. 删除头节点               5. 删除尾节点               6. 删除任意位置的节点\n");
        printf("7. 按值查找元素的位置       8. 按位置查找元素的值       9. 修改指定位置的节点值\n");
        printf("10. 修改指定值的节点值      11. 获取链表长度            12. 遍历链表\n");
        printf("13. 清空链表                14. 退出程序\n");
        printf("*********************************************************************\n");
        printf("请输入操作编号:");
        scanf("%d", &choice);

        char input[10];
        switch (choice) {
            case 1:
                while(1){
                    printf("请输入要插入的元素值(按q结束元素输入)):");
                    scanf("%s", input);

                    if (strcmp(input, "q") == 0) {
                        break;  // 退出循环
                    }

                    value = atoi(input);  // 将字符串转换为整数
                    //scanf("%d", &value);
                    insertAtHead(list, value);
                    printf("向后遍历:");
                    prev_traverse(list);
                    printf("向前遍历:");
                    next_traverse(list);
                }
                break;
            case 2:
                while(1){
                    printf("请输入要插入的元素值(按q结束元素输入)):");
                    scanf("%s", input);

                    if (strcmp(input, "q") == 0) {
                        break;  // 退出循环
                    }

                    value = atoi(input);  // 将字符串转换为整数

                    //printf("请输入要插入的元素值:");
                    //scanf("%d", &value);
                    insertAtTail(list, value);
                    printf("向后遍历:");
                    prev_traverse(list);
                    printf("向前遍历:");
                    next_traverse(list);
                }
                break;
            case 3:
                while(1){
                printf("请输入要插入的位置(按q结束元素输入):");
                    scanf("%s", input);

                    if (strcmp(input, "q") == 0) {
                        break;  // 退出循环
                    }

                    position = atoi(input);  // 将字符串转换为整数
                //scanf("%d", &position);
                printf("请输入要插入的元素值:");
                scanf("%d", &value);
                insertAtPosition(list, position, value);
                printf("向后遍历:");
                prev_traverse(list);
                printf("向前遍历:");
                next_traverse(list);
                }
                break;
            case 4:
                deleteHead(list);
                printf("向后遍历:");
                prev_traverse(list);
                printf("向前遍历:");
                next_traverse(list);
                break;
            case 5:
                deleteTail(list);
                printf("向后遍历:");
                prev_traverse(list);
                printf("向前遍历:");
                next_traverse(list);
                break;
            case 6:
                printf("请输入要删除的位置:");
                scanf("%d", &position);
                deleteAtPosition(list, position);
                printf("向后遍历:");
                prev_traverse(list);
                printf("向前遍历:");
                next_traverse(list);
                break;
            case 7:
                printf("请输入要查找的元素值:");
                scanf("%d", &value);
                position = findPositionByValue(list, value);
                if (position != -1) {
                    printf("元素值 %d 的位置是:%d\n", value, position);
                }
                break;
            case 8:
                printf("请输入要查找的位置:");
                scanf("%d", &position);
                value = findValueByPosition(list, position);
                if(!(position < 0 || position > (list->tail))){
                printf("位置 %d 上的元素值是:%d\n", position, value);
                }
                break;
            case 9:
                printf("请输入要修改的位置:");
                scanf("%d", &position);
                printf("请输入修改后的元素值:");
                scanf("%d", &value);
                modifyByPosition(list, position, value);
                printf("向后遍历:");
                prev_traverse(list);
                printf("向前遍历:");
                next_traverse(list);
                break;
            case 10:
                printf("请输入要修改的元素值:");
                scanf("%d", &oldValue);
                printf("请输入修改后的元素值:");
                scanf("%d", &newValue);
                modifyValue(list, oldValue, newValue);
                printf("向后遍历:");
                prev_traverse(list);
                printf("向前遍历:");
                next_traverse(list);
                break;
            case 11:
                printf("链表的长度是:%d\n", getLength(list));
                break;
            case 12:
                printf("向后遍历:");
                prev_traverse(list);
                printf("向前遍历:");
                next_traverse(list);
                break;
            case 13:
                clearList(list);
                break;
            case 14:
                printf("已退出!!\n");
                exit(0);
            default:
                printf("无效的操作编号!\n");
                break;
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小羊客栈

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

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

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

打赏作者

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

抵扣说明:

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

余额充值