当前位置: 首页 > news >正文

C语言中的双链表和单链表详细解释与实现

C语言中的双链表详细解释与实现

双链表(Doubly Linked List)是一种常见的数据结构,它比单链表更灵活,因为每个节点都包含指向前驱和后继节点的指针。

双链表的基本结构

节点定义

c

复制

下载

typedef struct Node {int data;           // 数据域struct Node* prev;  // 前驱指针struct Node* next;  // 后继指针
} Node;

双链表结构

c

复制

下载

typedef struct {Node* head;  // 头指针Node* tail;  // 尾指针int size;    // 链表长度
} DoublyLinkedList;

基本操作实现

1. 初始化双链表

c

复制

下载

void initList(DoublyLinkedList* list) {list->head = NULL;list->tail = NULL;list->size = 0;
}

2. 创建新节点

c

复制

下载

Node* createNode(int data) {Node* newNode = (Node*)malloc(sizeof(Node));if (newNode == NULL) {printf("内存分配失败!\n");exit(1);}newNode->data = data;newNode->prev = NULL;newNode->next = NULL;return newNode;
}

3. 在头部插入节点

c

复制

下载

void insertAtHead(DoublyLinkedList* list, int data) {Node* newNode = createNode(data);if (list->head == NULL) {  // 空链表list->head = list->tail = newNode;} else {newNode->next = list->head;list->head->prev = newNode;list->head = newNode;}list->size++;
}

4. 在尾部插入节点

c

复制

下载

void insertAtTail(DoublyLinkedList* list, int data) {Node* newNode = createNode(data);if (list->tail == NULL) {  // 空链表list->head = list->tail = newNode;} else {newNode->prev = list->tail;list->tail->next = newNode;list->tail = newNode;}list->size++;
}

5. 在指定位置插入节点

c

复制

下载

void insertAtPosition(DoublyLinkedList* list, int data, int position) {if (position < 0 || position > list->size) {printf("无效的位置!\n");return;}if (position == 0) {insertAtHead(list, data);} else if (position == list->size) {insertAtTail(list, data);} else {Node* newNode = createNode(data);Node* current = list->head;// 移动到要插入位置的前一个节点for (int i = 0; i < position - 1; i++) {current = current->next;}newNode->next = current->next;newNode->prev = current;current->next->prev = newNode;current->next = newNode;list->size++;}
}

6. 删除头节点

c

复制

下载

void deleteHead(DoublyLinkedList* list) {if (list->head == NULL) {printf("链表为空,无法删除!\n");return;}Node* temp = list->head;list->head = list->head->next;if (list->head == NULL) {  // 删除后链表为空list->tail = NULL;} else {list->head->prev = NULL;}free(temp);list->size--;
}

7. 删除尾节点

c

复制

下载

void deleteTail(DoublyLinkedList* list) {if (list->tail == NULL) {printf("链表为空,无法删除!\n");return;}Node* temp = list->tail;list->tail = list->tail->prev;if (list->tail == NULL) {  // 删除后链表为空list->head = NULL;} else {list->tail->next = NULL;}free(temp);list->size--;
}

8. 删除指定位置的节点

c

复制

下载

void deleteAtPosition(DoublyLinkedList* list, int position) {if (position < 0 || position >= list->size) {printf("无效的位置!\n");return;}if (position == 0) {deleteHead(list);} else if (position == list->size - 1) {deleteTail(list);} else {Node* current = list->head;// 移动到要删除的节点for (int i = 0; i < position; i++) {current = current->next;}current->prev->next = current->next;current->next->prev = current->prev;free(current);list->size--;}
}

9. 查找节点

c

复制

下载

Node* findNode(DoublyLinkedList* list, int data) {Node* current = list->head;while (current != NULL) {if (current->data == data) {return current;}current = current->next;}return NULL;  // 未找到
}

10. 打印链表(从头到尾)

c

复制

下载

void printListForward(DoublyLinkedList* list) {Node* current = list->head;printf("链表(正向): ");while (current != NULL) {printf("%d ", current->data);current = current->next;}printf("\n");
}

11. 打印链表(从尾到头)

c

复制

下载

void printListBackward(DoublyLinkedList* list) {Node* current = list->tail;printf("链表(反向): ");while (current != NULL) {printf("%d ", current->data);current = current->prev;}printf("\n");
}

12. 释放链表内存

c

复制

下载

void freeList(DoublyLinkedList* list) {Node* current = list->head;while (current != NULL) {Node* temp = current;current = current->next;free(temp);}list->head = list->tail = NULL;list->size = 0;
}

完整示例代码

c

复制

下载

#include <stdio.h>
#include <stdlib.h>typedef struct Node {int data;struct Node* prev;struct Node* next;
} Node;typedef struct {Node* head;Node* tail;int size;
} DoublyLinkedList;// 前面定义的所有函数在这里实现int main() {DoublyLinkedList list;initList(&list);// 插入操作insertAtHead(&list, 10);insertAtHead(&list, 20);insertAtTail(&list, 30);insertAtPosition(&list, 15, 1);insertAtPosition(&list, 25, 3);// 打印链表printListForward(&list);   // 输出: 链表(正向): 20 15 10 25 30 printListBackward(&list);  // 输出: 链表(反向): 30 25 10 15 20 // 查找操作Node* found = findNode(&list, 10);if (found != NULL) {printf("找到节点: %d\n", found->data);} else {printf("未找到节点\n");}// 删除操作deleteHead(&list);deleteTail(&list);deleteAtPosition(&list, 1);printListForward(&list);   // 输出: 链表(正向): 15 25 // 释放内存freeList(&list);return 0;
}

双链表的应用场景

  1. 浏览器历史记录:前进和后退功能

  2. 文本编辑器:撤销和重做操作

  3. 音乐播放器:上一曲和下一曲功能

  4. 实现双端队列(Deque)

  5. 更复杂的数据结构基础:如平衡树等

双链表的优缺点

优点

  • 可以双向遍历

  • 删除操作更高效(已知节点时O(1))

  • 插入操作更灵活

缺点

  • 每个节点需要额外空间存储前驱指针

  • 操作比单链表稍复杂

通过这个完整的C语言实现,你应该对双链表有了深入的理解。在实际编程中,可以根据需要扩展这些基本操作,例如添加排序、合并等功能。

单链表如下:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

// 学生信息结构体

typedef struct Student {

    int id;

    char name[20];

    int age;

    float score;

    struct Student *next;

} Student;

// 1. 创建链表

Student* createList() {

    Student *head = (Student*)malloc(sizeof(Student));

    if (head == NULL) {

        printf("内存分配失败!\n");

        exit(1);

    }

    head->next = NULL;

    return head;

}

// 2. 插入节点(头插法)

void insertNode(Student *head) {

    Student *newNode = (Student*)malloc(sizeof(Student));

    if (newNode == NULL) {

        printf("内存分配失败!\n");

        return;

    }

   

    printf("请输入学号: ");

    scanf("%d", &newNode->id);

    printf("请输入姓名: ");

    scanf("%s", newNode->name);

    printf("请输入年龄: ");

    scanf("%d", &newNode->age);

    printf("请输入成绩: ");

    scanf("%f", &newNode->score);

   

    newNode->next = head->next;

    head->next = newNode;

   

    printf("添加成功!\n");

}

// 3. 删除节点(根据学号)

void deleteNode(Student *head, int id) {

    Student *p = head->next;

    Student *prev = head;

   

    while (p != NULL) {

        if (p->id == id) {

            prev->next = p->next;

            free(p);

            printf("删除成功!\n");

            return;

        }

        prev = p;

        p = p->next;

    }

   

    printf("未找到学号为%d的学生!\n", id);

}

// 4. 查找学生信息

void searchStudent(Student *head, int id) {

    Student *p = head->next;

   

    while (p != NULL) {

        if (p->id == id) {

            printf("学号: %d, 姓名: %s, 年龄: %d, 成绩: %.2f\n",

                   p->id, p->name, p->age, p->score);

            return;

        }

        p = p->next;

    }

   

    printf("未找到学号为%d的学生!\n", id);

}

// 5. 打印整个链表

void printList(Student *head) {

    Student *p = head->next;

   

    if (p == NULL) {

        printf("链表为空!\n");

        return;

    }

   

    printf("学生信息如下:\n");

    printf("学号\t姓名\t年龄\t成绩\n");

    while (p != NULL) {

        printf("%d\t%s\t%d\t%.2f\n", p->id, p->name, p->age, p->score);

        p = p->next;

    }

}

// 6. 计算链表长度

int listLength(Student *head) {

    int count = 0;

    Student *p = head->next;

   

    while (p != NULL) {

        count++;

        p = p->next;

    }

   

    return count;

}

// 7. 清空链表

void clearList(Student *head) {

    Student *p = head->next;

    Student *temp;

   

    while (p != NULL) {

        temp = p;

        p = p->next;

        free(temp);

    }

   

    head->next = NULL;

    printf("链表已清空!\n");

}

// 主函数

int main() {

    Student *head = createList();

    int choice, id;

   

    while (1) {

        printf("\n学生信息管理系统\n");

        printf("1. 添加学生\n");

        printf("2. 删除学生\n");

        printf("3. 查找学生\n");

        printf("4. 显示所有学生\n");

        printf("5. 统计学生人数\n");

        printf("6. 清空链表\n");

        printf("0. 退出\n");

        printf("请选择操作: ");

        scanf("%d", &choice);

       

        switch (choice) {

            case 1:

                insertNode(head);

                break;

            case 2:

                printf("请输入要删除的学生学号: ");

                scanf("%d", &id);

                deleteNode(head, id);

                break;

            case 3:

                printf("请输入要查找的学生学号: ");

                scanf("%d", &id);

                searchStudent(head, id);

                break;

            case 4:

                printList(head);

                break;

            case 5:

                printf("当前共有%d名学生\n", listLength(head));

                break;

            case 6:

                clearList(head);

                break;

            case 0:

                clearList(head);

                free(head);

                printf("程序已退出!\n");

                return 0;

            default:

                printf("无效的选择!\n");

        }

    }

   

    return 0;

}

算法说明

  1. 链表结构:使用带头节点的单链表结构,头节点不存储数据,仅作为链表起始标志。
  2. 插入操作:采用头插法,新节点总是插入到头节点之后,时间复杂度O(1)。
  3. 删除操作:根据学号查找并删除节点,需要遍历链表,时间复杂度O(n)。
  4. 查找操作:根据学号线性查找,时间复杂度O(n)。
  5. 内存管理:每个节点动态分配内存,清空链表时需要逐个释放。
  6. 用户交互:通过简单的菜单系统实现功能选择。
http://www.xdnf.cn/news/64171.html

相关文章:

  • PostgreSQL 用户资源管理
  • 基于LLM的响应式流式处理实践:提升用户体验的关键技术
  • 【python】copy deepcopy 赋值= 对比
  • el-input 限制只能输入非负数字和小数
  • 基于SIMMECHANICS的单自由度磁悬浮隔振器PID控制系统simulink建模与仿真
  • linux基础学习--linux文件与目录管理
  • 【python实用小脚本系列】用Python打造你的专属智能语音助手
  • 【技术派后端篇】技术派中基于 Redis 的缓存实践
  • 快手砍掉本地生活的门槛
  • Redis的使用总结
  • 电脑硬盘常见的几种接口类型
  • 方案精读:2024 华为数字政府智慧政务一网统管解决方案【附全文阅读】
  • Flowable7.x学习笔记(十)分页查询已部署 BPMN XML 流程
  • 博奥龙全系方案护航科研命脉
  • 让数据应用更简单:Streamlit与Gradio的比较与联系
  • AI音乐解决方案:1分钟可切换suno、udio、luno、kuka等多种模型,suno风控秒切换 | AI Music API
  • 基于瑞芯微RK3576国产ARM八核2.2GHz A72 工业评估板——ROS2系统使用说明
  • IDEA/WebStorm中Git操作缓慢的解决方案
  • OSPF --- LSA
  • elasticsearch7.15节点磁盘空间满了迁移数据到新磁盘
  • LangChain与图数据库Neo4j LLMGraphTransformer融合:医疗辅助诊断、金融风控领域垂直领域、法律咨询场景问答系统的技术实践
  • WebRTC通信技术EasyRTC音视频实时通话安全巡检搭建低延迟、高可靠的智能巡检新体系
  • docker学习笔记2-最佳实践
  • 腾讯一面-软件开发实习-PC客户端开发方向
  • 龙虎榜——20250421
  • 【前端样式】用 aspect-ratio 实现等比容器:视频封面与图片占位的终极解决方案
  • 基于超启发鲸鱼优化算法的混合神经网络多输入单输出回归预测模型 HHWOA-CNN-LSTM-Attention
  • 计算机组成与体系结构:内存层次结构(Memory Hierarchy)
  • # 04_Elastic Stack 从入门到实践(四)--3
  • 项目班——0419——functionbind生产消费(未完成)