• C/C++数据结构之深入了解线性表:顺序表、单链表、循环链表和双向链表


    线性表是一种基本的数据结构,它在计算机科学中起着至关重要的作用。线性表用于存储一系列具有相同数据类型的元素,这些元素之间存在顺序关系。在C/C++中,我们可以使用各种方式来实现线性表,其中包括顺序表、单链表、循环链表和双向链表。本篇博客将深入探讨这些数据结构的概念,并通过示例代码进行详细分析。

    什么是线性表?

    线性表是一种抽象数据类型,它表示具有相同数据类型的元素的有序集合。线性表中的元素之间存在明确的线性顺序,通常由一个首元素和一个尾元素界定。线性表的常见操作包括插入、删除、查找和遍历。在C/C++中,线性表可以通过数组或链表来实现。

    顺序表(Array)

    顺序表是一种使用数组来实现的线性表,其中元素在内存中是连续存储的。这使得顺序表具有O(1)时间复杂度的随机访问特性,但在插入和删除操作时可能需要移动大量元素。顺序表的大小通常是固定的,除非重新分配内存。

    顺序表的定义

    在C/C++中,顺序表可以定义如下:

    1. #include
    2. #define MAX_SIZE 100 // 顺序表的最大容量
    3. typedef struct {
    4. int data[MAX_SIZE]; // 数据存储数组
    5. int length; // 当前长度
    6. } SeqList;

    顺序表的示例

    以下是一个简单的C程序,用于初始化、插入和遍历顺序表:

    1. #include
    2. #define MAX_SIZE 100
    3. typedef struct {
    4. int data[MAX_SIZE];
    5. int length;
    6. } SeqList;
    7. // 初始化顺序表
    8. void init(SeqList *list) {
    9. list->length = 0;
    10. }
    11. // 在指定位置插入元素
    12. int insert(SeqList *list, int position, int element) {
    13. if (position < 0 || position > list->length || list->length >= MAX_SIZE) {
    14. return 0; // 插入失败
    15. }
    16. for (int i = list->length; i > position; i--) {
    17. list->data[i] = list->data[i - 1];
    18. }
    19. list->data[position] = element;
    20. list->length++;
    21. return 1; // 插入成功
    22. }
    23. // 遍历顺序表
    24. void traverse(SeqList *list) {
    25. for (int i = 0; i < list->length; i++) {
    26. printf("%d ", list->data[i]);
    27. }
    28. printf("\n");
    29. }
    30. int main() {
    31. SeqList list;
    32. init(&list);
    33. insert(&list, 0, 1);
    34. insert(&list, 1, 2);
    35. insert(&list, 2, 3);
    36. traverse(&list);
    37. return 0;
    38. }

    这段代码演示了如何初始化顺序表、在指定位置插入元素以及遍历顺序表。输出将是 1 2 3

    单链表(Singly Linked List)

    单链表是一种通过节点之间的指针链接来实现的线性表。每个节点包含数据元素和一个指向下一个节点的指针。单链表不要求内存中的节点是连续的,因此插入和删除操作比顺序表更高效。

    单链表的定义

    在C/C++中,单链表可以定义如下:

    1. #include
    2. typedef struct Node {
    3. int data; // 数据元素
    4. struct Node *next; // 指向下一个节点的指针
    5. } ListNode;

    单链表的示例

    以下是一个简单的C程序,用于初始化、插入和遍历单链表:

    1. #include
    2. #include
    3. typedef struct Node {
    4. int data;
    5. struct Node *next;
    6. } ListNode;
    7. // 初始化单链表
    8. ListNode *init() {
    9. return NULL;
    10. }
    11. // 在链表末尾插入元素
    12. ListNode *insert(ListNode *head, int element) {
    13. ListNode *newNode = (ListNode *)malloc(sizeof(ListNode));
    14. if (newNode == NULL) {
    15. perror("Memory allocation failed");
    16. exit(1);
    17. }
    18. newNode->data = element;
    19. newNode->next = NULL;
    20. if (head == NULL) {
    21. return newNode;
    22. }
    23. ListNode *current = head;
    24. while (current->next != NULL) {
    25. current = current->next;
    26. }
    27. current->next = newNode;
    28. return head;
    29. }
    30. // 遍历单链表
    31. void traverse(ListNode *head) {
    32. ListNode *current = head;
    33. while (current != NULL) {
    34. printf("%d ", current->data);
    35. current = current->next;
    36. }
    37. printf("\n");
    38. }
    39. // 释放单链表的内存
    40. void destroy(ListNode *head) {
    41. while (head != NULL) {
    42. ListNode *temp = head;
    43. head = head->next;
    44. free(temp);
    45. }
    46. }
    47. int main() {
    48. ListNode *head = init();
    49. head = insert(head, 1);
    50. head = insert(head, 2);
    51. head = insert(head, 3);
    52. traverse(head);
    53. destroy(head);
    54. return 0;
    55. }

    这段代码演示了如何初始化单链表、在链表末尾插入元素以及遍历单链表。输出将是 1 2 3

    循环链表(Circular Linked List)

    循环链表是一种单链表的变体,其中最后一个节点的指针指向第一个节点,形成一个循环。循环链表可以用于解决环形问题,如约瑟夫问题(Josephus Problem)。

    循环链表的定义

    循环链表的定义与单链表类似,唯一不同之处在于最后一个节点的指针指向第一个节点。

    1. #include
    2. typedef struct Node {
    3. int data;
    4. struct Node *next;
    5. } CircularListNode;

    循环链表的示例

    以下是一个简单的C程序,用于初始化、插入和遍历循环链表:

    1. #include
    2. #include
    3. typedef struct Node {
    4. int data;
    5. struct Node *next;
    6. } CircularListNode;
    7. // 初始化循环链表
    8. CircularListNode *init() {
    9. return NULL;
    10. }
    11. // 在链表末尾插入元素
    12. CircularListNode *insert(CircularListNode *head, int element) {
    13. CircularListNode *newNode = (CircularListNode *)malloc(sizeof(CircularListNode));
    14. if (newNode == NULL) {
    15. perror("Memory allocation failed");
    16. exit(1);
    17. }
    18. newNode->data = element;
    19. newNode->next = NULL;
    20. if (head == NULL) {
    21. newNode->next = newNode; // 指向自己形成循环
    22. return newNode;
    23. }
    24. CircularListNode *current = head;
    25. while (current->next != head) {
    26. current = current->next;
    27. }
    28. current->next = newNode;
    29. newNode->next = head; // 最后一个节点指向头节点形成循环
    30. return head;
    31. }
    32. // 遍历循环链表
    33. void traverse(CircularListNode *head) {
    34. if (head == NULL) {
    35. return;
    36. }
    37. CircularListNode *current = head;
    38. do {
    39. printf("%d ", current->data);
    40. current = current->next;
    41. } while (current != head);
    42. printf("\n");
    43. }
    44. // 释放循环链表的内存
    45. void destroy(CircularListNode *head) {
    46. if (head == NULL) {
    47. return;
    48. }
    49. CircularListNode *current = head;
    50. CircularListNode *temp;
    51. do {
    52. temp = current;
    53. current = current->next;
    54. free(temp);
    55. } while (current != head);
    56. }
    57. int main() {
    58. CircularListNode *head = init();
    59. head = insert(head, 1);
    60. head = insert(head, 2);
    61. head = insert(head, 3);
    62. traverse(head);
    63. destroy(head);
    64. return 0;
    65. }

    这段代码演示了如何初始化循环链表、在链表末尾插入元素以及遍历循环链表。输出将是 1 2 3,并形成循环。

    双向链表(Doubly Linked List)

    双向链表是一种链表,每个节点包含两个指针,一个指向前一个节点,一个指向后一个节点。这种结构使得在双向链表中可以轻松地进行双向遍历,但相对于单链表,它需要更多的内存空间来存储额外的指针。

    双向链表的定义

    在C/C++中,双向链表可以定义如下:

    1. #include
    2. typedef struct Node {
    3. int data;
    4. struct Node *prev; // 指向前一个节点的指针
    5. struct Node *next; // 指向后一个节点的指针
    6. } DoublyListNode;

    双向链表的示例

    以下是一个简单的C程序,用于初始化、插入和遍历双向链表:

    1. #include
    2. #include
    3. typedef struct Node {
    4. int data;
    5. struct Node *prev;
    6. struct Node *next;
    7. } DoublyListNode;
    8. // 初始化双向链表
    9. DoublyListNode *init() {
    10. return NULL;
    11. }
    12. // 在链表末尾插入元素
    13. DoublyListNode *insert(DoublyListNode *head, int element) {
    14. DoublyListNode *newNode = (DoublyListNode *)malloc(sizeof(DoublyListNode));
    15. if (newNode == NULL) {
    16. perror("Memory allocation failed");
    17. exit(1);
    18. }
    19. newNode->data = element;
    20. newNode->prev = NULL;
    21. newNode->next = NULL;
    22. if (head == NULL) {
    23. return newNode;
    24. }
    25. DoublyListNode *current = head;
    26. while (current->next != NULL) {
    27. current = current->next;
    28. }
    29. newNode->prev = current;
    30. current->next = newNode;
    31. return head;
    32. }
    33. // 遍历双向链表(正向)
    34. void traverseForward(DoublyListNode *head) {
    35. DoublyListNode *current = head;
    36. while (current != NULL) {
    37. printf("%d ", current->data);
    38. current = current->next;
    39. }
    40. printf("\n");
    41. }
    42. // 遍历双向链表(反向)
    43. void traverseBackward(DoublyListNode *head) {
    44. DoublyListNode *current = head;
    45. while (current->next != NULL) {
    46. current = current->next;
    47. }
    48. while (current != NULL) {
    49. printf("%d ", current->data);
    50. current = current->prev;
    51. }
    52. printf("\n");
    53. }
    54. // 释放双向链表的内存
    55. void destroy(DoublyListNode *head) {
    56. DoublyListNode *current = head;
    57. DoublyListNode *temp;
    58. while (current != NULL) {
    59. temp = current;
    60. current = current->next;
    61. free(temp);
    62. }
    63. }
    64. int main() {
    65. DoublyListNode *head = init();
    66. head = insert(head, 1);
    67. head = insert(head, 2);
    68. head = insert(head, 3);
    69. traverseForward(head);
    70. traverseBackward(head);
    71. destroy(head);
    72. return 0;
    73. }

    这段代码演示了如何初始化双向链表、在链表末尾插入元素以及正向和反向遍历双向链表。输出将是 1 2 33 2 1


    了解更多内容获取更多相关资源前往公众号:每日推荐系列


    总结

    线性表是计算机科学中常见的数据结构,用于存储一系列具有相同数据类型的元素。在C/C++中,我们可以使用不同的数据结构来实现线性表,包括顺序表、单链表、循环链表和双向链表。每种数据结构都有其独特的特点和适用场景,根据具体需求选择合适的数据结构是非常重要的。

  • 相关阅读:
    详细指南:使用C语言控制TI ADS1262和ADS1263模数转换器
    SSM框架学习
    lnmp架构之mysql部署
    视频怎么制作成gif动画?这个方法试试看
    linux常用指令
    transformer一统天下?depth-wise conv有话要说
    竞赛选题 深度学习验证码识别 - 机器视觉 python opencv
    【前端学java】Java中的异常处理(15)完结
    计算机操作系统 (王道考研)笔记(三)文件
    jsp交通管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
  • 原文地址:https://blog.csdn.net/qq_72290695/article/details/134095048