详细介绍C语言中双向不循环链表的实现和基本操作

1、双向不循环链表的定义和结构
2、判断链表是否为空
3、创建双向不循环链表
4、在双向不循环链表中插入节点
5、从双向不循环链表中删除节点
6、查找链表的元素或元素的下标
7、修改链表的元素
8、获取链表的长度
9、遍历双向不循环链表
10、释放双向不循环链表的内存
11、完整代码

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

我们将解释双向不循环链表的概念,并说明每个节点的结构。每个节点包含一个数据元素,一个指向前一个节点的指针(prev),以及一个指向下一个节点的指针(next)。

// 链表节点结构体
typedef struct Node {
    typData data;// 节点数据
    int tail;//记录节点数
    struct Node *prev;//指向上一个节点的指针
    struct Node *next;//指向下一个节点的指针
} Linklist, *Plinklist;
int isEmpty(Plinklist list){
    if(list == NULL || list->tail == 0){
        //puts("表是空的!");
        return 1;//真空
    }else{
        return 0;//非空

我们将介绍如何创建一个空的双向不循环链表,并确保头节点的正确设置。
初始化(创建):表头不存放数据

// 创建链表
Plinklist createLinkedList(Plinklist *list){
    (*list) = (Plinklist)malloc(sizeof(Linklist));//为表头申请空间
    if(list == NULL){
        perror("createLinkedList list malloc");
    (*list)->tail = 0;//记录节点数
    (*list)->prev = NULL;//头节点的上一个节点置空
    (*list)->next = NULL;//头节点的下一个节点置空
    return *list;

我们将讨论在链表的头部、尾部和任意插入节点的方法。这包括更新指针和调整节点的链接。
头插法
在这里插入图片描述

// 在链表头部插入元素
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;//设置新节点的数据值
    newNode->prev = list;//新节点的prev指针指向头节点
    newNode->next = list->next;//新节点的next指针的作用是替代头节点的next指针指向NULL
    if(list->next != NULL){
        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 = NULL;// 新节点的后继节点指向NULL
    Plinklist current_tail = list;// 重新定义一个新指针指向头节点
    while(current_tail->next != NULL){
        current_tail = current_tail->next;// 遍历找到链表的尾节点
    newNode->prev = current_tail;// 新节点的前驱节点指向尾节点
    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 != NULL && count < position){
        current = current->next;// 找到要插入位置的前一个节点
        count++;
    newNode->next = current->next;// 新节点的后继指向要原删除节点的前一节点的下一个节点
    newNode->prev = current;// 新节点的前驱指向新节点的前一节点
    if (current->next != NULL) {
        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 != NULL) {
        deleteHead->next->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 != NULL && current->next->next != NULL){
        current = current->next; 找到尾节点
    Plinklist deleteTail = current->next;
    current->next = NULL;// 要删除节点的上一个节点的后继直接连接NULL,断开要删除节点和NULL的连接
    if (deleteTail != NULL) {// 判断要删除节点是否为空
        free(deleteTail);//不为空则释放该删除节点的内存
        list->tail--;// 节点数减一

删除任意下标的节点
在这里插入图片描述

// 删除指定位置的节点
void deleteAtPosition(Plinklist list, int position){
    if (isEmpty(list)) {
        printf("链表为空,删不了,根本删不了\n");
        return;
    Plinklist current = list;  // 从头节点开始遍历链表,找到要删除节点的前一个节点
    int count = 0;
    while (current->next != NULL && count < position) {
        current = current->next;// 不断更新current指针
        count++;
    if (current->next == NULL) {// 检查删除位置的有效性
        printf("无效的删除位置\n");
        return;
    Plinklist deletePosition = current->next;//定义新的指针记录要删除节点的上一个节点
    current->next = deletePosition->next;// 要删除节点的上一个节点的后继连接到要删除节点的后一个节点,断开要删除节点的和要删除节点
的上一个节点的后继
    if (deletePosition->next != NULL) {
        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 != NULL) {
        if (current->data == value) {
            return position;  // 找到节点的数据值等于目标值,返回节点的下标
        current = current->next;
        position++;
    printf("没有该值!");
    return -1;  // 未找到目标值,返回-1

按元素下标查找该下标的元素值

// 按下标查找节点的值
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 != NULL && count < position) {
        current = current->next;
        count++;
    if (current == NULL) {// 检查下标的有效性
        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)){
        puts("表是空的!");
        return ;
    if (isEmpty(list)) {
        printf("链表为空,无法修改元素\n");
        return;
    Plinklist current = list->next;  // 从第一个节点开始遍历链表
    int count = 0;
    while (current != NULL && count < position) {
        current = current->next;
        count++;
    if (current == NULL) {
        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 != NULL) {
        if (current->data == oldValue) {
            current->data = newValue;  // 找到节点的数据值等于旧值,更新节点的数据值为新值
            return;
        current = current->next;
    printf("未找到目标值\n");

8、获取链表的长度

// 获取链表长度
int getLength(Plinklist list){
    if(isEmpty(list)){
        return -1;
    return list->tail;//直接返回链表的tail节点数

9、遍历双向不循环链表:

我们将展示如何遍历链表并访问每个节点的数据元素。我们将演示前向后向遍历的方法。
向后遍历:从尾节点遍历到头节点

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

向前遍历:从头节点遍历到尾节点

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

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

我们将讨论如何正确释放整个链表所占用的内存。
我们调用前面的删除头节点的方法。不断删除头节点直到链表为空
在这里插入图片描述

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

分三个文件进行,①接口文件blinklist.h、②blinklist.c、③blinklist_main.c

①blinklist.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

②blinklist.c

#include "blinklist.h"
// 链表节点结构体
typedef struct Node {
    typData data;// 节点数据
    int tail;//记录节点数
    struct Node *prev;//指向上一个节点的指针
    struct Node *next;//指向下一个节点的指针
} Linklist, *Plinklist;
// 创建链表
Plinklist createLinkedList(Plinklist *list){
    (*list) = (Plinklist)malloc(sizeof(Linklist));//为表头申请空间
    if(list == NULL){
        perror("createLinkedList list malloc");
    (*list)->tail = 0;//记录节点数
    (*list)->prev = NULL;//头节点的上一个节点置空
    (*list)->next = NULL;//头节点的下一个节点置空
    return *list;
// 判断链表是否为空
int isEmpty(Plinklist list){
    if(list == NULL || 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;//设置新节点的数据值
    newNode->prev = list;//新节点的prev指针指向头节点
    newNode->next = list->next;//新节点的next指针的作用是替代头节点的next指针指向NULL
    if(list->next != NULL){
        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 = NULL;// 新节点的后继节点指向NULL
    Plinklist current_tail = list;// 重新定义一个新指针指向头节点
    while(current_tail->next != NULL){
        current_tail = current_tail->next;// 遍历找到链表的尾节点
    newNode->prev = current_tail;// 新节点的前驱节点指向尾节点
    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 != NULL && count < position){
        current = current->next;// 找到要插入位置的前一个节点
        count++;
    newNode->next = current->next;// 新节点的后继指向要原删除节点的前一节点的下一个节点
    newNode->prev = current;// 新节点的前驱指向新节点的前一节点
    if (current->next !=




    
 NULL) {
        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 != NULL) {
        deleteHead->next->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 != NULL && current->next->next != NULL){
        current = current->next; 找到尾节点
    Plinklist deleteTail = current->next;
    current->next = NULL;// 要删除节点的上一个节点的后继直接连接NULL,断开要删除节点和NULL的连接
    if (deleteTail != NULL) {// 判断要删除节点是否为空
        free(deleteTail);//不为空则释放该删除节点的内存
        list->tail--;// 节点数减一
// 删除指定位置的节点
void deleteAtPosition(Plinklist list, int position){
    if (isEmpty(list)) {
        printf("链表为空,删不了,根本删不了\n");
        return;
    Plinklist current = list;  // 从头节点开始遍历链表,找到要删除节点的前一个节点
    int count = 0;
    while (current->next != NULL && count < position) {
        current = current->next;// 不断更新current指针
        count++;
    if (current->next == NULL) {// 检查删除位置的有效性
        printf("无效的删除位置\n");
        return;
    Plinklist deletePosition = current->next;//定义新的指针记录要删除节点的上一个节点
    current->next = deletePosition->next;// 要删除节点的上一个节点的后继连接到要删除节点的后一个节点,断开要删除节点的和要删除节点的上一个节点的后继
    if (deletePosition->next != NULL) {
        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 != NULL) {
        if (current->data == value) {
            return position;  // 找到节点的数据值等于目标值,返回节点的下标
        current = current->next;
        position++;
    printf("没有该值!");
    return -1;  // 未找到目标值,返回-1
// 按下标查找节点的值
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 != NULL && count < position) {
        current = current->next;
        count++;
    if (current == NULL) {// 检查下标的有效性
        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)){
        puts("表是空的!");
        return ;
    if (isEmpty(list)) {
        printf("链表为空,无法修改元素\n");
        return;
    Plinklist current = list->next;  // 从第一个节点开始遍历链表
    int count = 0;
    while (current != NULL && count < position) {
        current = current->next;
        count++;
    if (current == NULL) {
        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 != NULL) {
        if (current->data == oldValue) {
            current->data = newValue;  // 找到节点的数据值等于旧值,更新节点的数据值为新值
            return;
        current = current->next;
    printf("未找到目标值\n");
// 获取链表长度
int getLength(Plinklist list){
    if(isEmpty(list)){
        return -1;
    return list->tail;
//向后遍历链表并打印节点值(从尾节点遍历到头节点)
void prev_traverse(Plinklist list){
    if(list == NULL){
        puts("prev_traverse arg err");
        return ;
    if(isEmpty(list)){
        return ;
    Plinklist current_tail = list;
    while(current_tail->next != NULL){
        current_tail = current_tail->next;// 找到尾节点
    Plinklist current = current_tail;
    while(current != list){
        printf("%d ",current->data);// 打印节点值
        current = current->prev;
    printf("\n");
//向前遍历链表并打印节点值(从头节点遍历到尾节点)
void next_traverse(Plinklist list){
    if(list == NULL){
        puts("next_traverse arg err");
        return ;
    if(isEmpty(list)){
        return ;
    Plinklist current = list->next;
    while (current != NULL) {
        printf("%d ", current->data);
        current = current->next;
    printf("\n");
// 清空链表
void clearList(Plinklist list){
    while(list->next != NULL){
        deleteHead(list);//调用删除头节点函数,实现不断的删除头节点
    printf("表已被清空!\n");

③blinklist_main.c

#include "blinklist.h"
#include "blinklist.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);
        switch (choice) {
            case 1:
                printf("请输入要插入的元素值:");
                scanf("%d", &value);
                insertAtHead(list, value);
                printf("向后遍历:");
                prev_traverse




    
(list);
                printf("向前遍历:");
                next_traverse(list);
                break;
            case 2:
                printf("请输入要插入的元素值:");
                scanf("%d", &value);
                insertAtTail(list, value);
                printf("向后遍历:");
                prev_traverse(list);
                printf("向前遍历:");
                next_traverse(list);
                break;
            case 3:
                printf("请输入要插入的位置:");
                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 (value != -1) {
                    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;
                    我们将解释双向不循环链表的概念,并说明每个节点的结构。每个节点包含一个数据元素,一个指向前一个节点的指针(prev),以及一个指向下一个节点的指针(next)。四、数据结构——单向链表的基本操作详解:创建、插入(头插法、尾插法、任意点插法)、删除(头删法、尾删法、任意位置删法)、查询(按值查下标、按下标查值)、遍历链表和清空链表
这里的顺序比较容易记住,就是自己写代码的时候可能会比较迷糊,我是这样记得,箭从起到终的方向为等式的左边,箭的终为等式的右边,拿①举例子,箭的方向为node->prev,箭的终为head,所以第一步为node->prev = head。
Node * node = new Node;
				
文章目录1.头插法2.尾插法3.删除元素4.打印元素总结 链表是一种常见的基础数据结构,结构体指针,下面用c语言实现单链表插入删除,打印等基本操作 1.头插法 头插法:从一个空表开始,重复读入数据,生成新节,将读入的数据域存放到新结的数据域中,然后将新结插入到当前链表的表之后,直至读入结束为止 头插法图解 头插法代码 //插入元素(头插法) int insertheadList...
链表的一个优是结构简单,但是它也有一个缺,即在单链表中只能通过一个结的引用访问其后续结,而无法直接访问其前驱结, 要在单链表中找到某个结的前驱结,必须从链表的首结出发依次向后寻找,但是需要Ο(n)时间。 为此我们可以扩展单链表的结结构,使得通过一个结的引用,不但能够访问其后续结,也可以方便的访问其前驱结。 扩展单链表结构的方法是,在单链表结构中新增加一...
双向链表的操作问题 Description 建立一个长度为n的带双向链表,使得该链表中的数据元素递增有序排列。(必须使用双向链表完成,数据类型为整型。) Input 第一行:双向表的长度; 第二行:链表中的数据元素。 Output 输出双向链表中的数据元素的值。 Sample Input 2 4 6 3 5 8 10 21 12 9Sample
上午写了下单向循环链表的程序,今天下午我把双向链表的程序写完了。其实双向链表和单向链表也是有很多相似的地方的,听名字可以猜到,每个节都包含两个指针,一个指针指向上一个节,一个指针指向下一个节。这里有两个特殊的地方,第一就是的一个指针指向NULL空指针(没有前驱节),第二就是的一个指针指向NULL指针(没有后继节)。 我们可以看下双向链表的示意图(自己画的比较难看):
头插法尾插法是在链表数据结构中常见的两种插入元素的方法。 头插法的核心思想是将新节插入链表部。在带方式实现头插法时,首先创建一个新节,并将新节的next指针指向当前链表,再将指向新节。而在不带方式实现头插法时,直接将新节的next指针指向当前链表,再将指向新节尾插法的核心思想是将新节插入链表部。在带方式实现尾插法时,首先创建一个新节,并将新节的next指针置为NULL,然后找到链表,将的next指针指向新节。而在不带方式实现尾插法时,先判断链表是否为空,若为空则将新节作为链表,否则找到链表,将的next指针指向新节。 关于代码实现,可以利用结构体和指针来定义链表数据结构,如引用所示。然后根据需要选择头插法尾插法,使用相关的代码段来实现插入操作,如引用所示。具体的插入过程中,可以根据具体需求在新节中设置相关的数据信息。最后,通过运行程序可以得到链表插入操作的结果。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【数据结构】:单链表头插法尾插法(动图+图解)](https://blog.csdn.net/weixin_46629453/article/details/125643226)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [链表的三种插入方法(头插法尾插法任意位置插入)](https://blog.csdn.net/weixin_63032791/article/details/122089859)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]