• 【数据结构】链表C++编写的,它定义了一个链表,并实现了一些基本的链表操作,如创建新节点、插入节点、清空链表、输出链表以及查找节点


    1. // 引入标准输入输出流库,用于输出操作
    2. #include
    3. // 引入标准库中的stdlib,包含了rand()函数和其他相关函数
    4. #include
    5. // 引入标准库中的time,包含了time()函数和其他相关函数
    6. #include
    7. // 定义常量DL为3,表示链表每个节点占用的字符宽度
    8. #define DL 3
    9. // 使用宏定义一个字符串化运算符,用于将数字转化为字符串
    10. #define STR(n) #n
    11. // 使用宏定义一个格式化字符串,用于输出特定长度的整数,例如"%3d"表示输出的整数占用三个字符长度
    12. #define DIGIT_LEN_STR(n) "%" STR(n) "d"
    13. // 定义一个结构体Node,表示链表中的节点
    14. struct Node {
    15. int data; // 节点的数据域,存储节点的值
    16. Node* next; // 指向下一个节点的指针
    17. };
    18. // 定义一个函数,用于创建一个新的节点,并返回该节点的指针
    19. Node* getNewNode(int val) {
    20. // 动态分配一个新的Node内存空间,并返回其指针
    21. Node* p = new Node;
    22. // 设置新节点的数据域为传入的值
    23. p->data = val;
    24. // 将新节点的next指针设置为nullptr,表示该节点为链表的末尾
    25. p->next = nullptr;
    26. // 返回新节点的指针
    27. return p;
    28. }
    29. // 定义一个函数,用于在链表的指定位置插入一个新的节点
    30. Node* insert(Node* head, int pos, int val) {
    31. // 创建一个新的头节点new_head,并创建一个新的节点node
    32. Node new_head, *p = &new_head, *node = getNewNode(val);
    33. // 将new_head的next指针指向当前的head,形成一个新的链表
    34. new_head.next = head;
    35. // 通过循环移动p指针到指定位置的前一个节点
    36. for (int i = 0; i < pos; i++) {
    37. p = p->next;
    38. }
    39. // 将node的next指针指向p的下一个节点,实现插入操作
    40. node->next = p->next;
    41. // 将p的下一个节点设置为node,完成插入操作
    42. p->next = node;
    43. // 返回新的链表的头节点的指针
    44. return new_head.next;
    45. }
    46. // 定义一个函数,用于清空链表中的所有节点,释放其内存空间
    47. void clear(Node* head) {
    48. // 如果链表为空,则直接返回
    49. if (head == nullptr) {
    50. return;
    51. }
    52. // 定义两个指针p和q,p用于遍历链表,q用于保存下一个节点
    53. Node *p = head, *q;
    54. // 当p非空时,执行以下操作
    55. while (p) {
    56. // 保存p的下一个节点为q
    57. q = p->next;
    58. // 释放p的内存空间
    59. delete p;
    60. // 将p移动到下一个节点
    61. p = q;
    62. }
    63. }
    64. // 输出链表函数开始
    65. void output_linklist(Node* head, int flag = 0) {
    66. // 初始化计数器n为0
    67. int n = 0;
    68. // 遍历链表,计算链表中节点的数量,并累加到n中
    69. for (Node* p = head; p; p = p->next) {
    70. n += 1;
    71. }
    72. // 输出每行的前缀,表示节点的位置,使用特定长度的整数格式化字符串输出n的值,并在后面加上空格
    73. for (int i = 0; i < n; i++) {
    74. std::cout << i << " ";
    75. }
    76. // 输出换行符,表示一行的结束
    77. std::cout << std::endl;
    78. // 遍历链表,输出每个节点的值和它连接的下一个节点,使用字符串化运算符将整数转化为字符串并输出,最后输出箭头符号"->"表示连接关系
    79. for (Node* p = head; p; p = p->next) {
    80. std::cout << p->data << "->";
    81. }
    82. // 输出换行符,表示一行的结束
    83. std::cout << std::endl;
    84. // 如果flag等于0,则输出一个额外的换行符
    85. if (flag == 0) {
    86. std::cout << std::endl;
    87. }
    88. // 输出链表函数结束
    89. }
    90. // 定义一个函数,用于在链表中查找指定值的节点
    91. int find(Node* head, int val) {
    92. // 定义一个指针p,指向链表的头节点
    93. Node* p = head;
    94. // 初始化计数器n为0
    95. int n = 0;
    96. // 遍历链表,直到p为空(链表结束)
    97. while (p) {
    98. // 如果当前节点的值等于目标值val
    99. if (p->data == val) {
    100. // 调用output_linklist函数输出整个链表,参数为head和1(表示需要输出找到的节点)
    101. output_linklist(head, 1);
    102. // 计算找到的节点在链表中的位置,长度为n*(DL+2)+2
    103. int len = n * (DL + 2) + 2;
    104. // 输出一些空格,用于画出一个矩形框来标记找到的节点
    105. for (int i = 0; i < len; i++) std::cout << " ";
    106. // 输出一个竖线,用于标记找到的节点在矩形框中的位置
    107. std::cout << "^\n";
    108. // 再输出一些空格,用于画出矩形框的底部
    109. for (int i = 0; i < len; i++) std::cout << " ";
    110. // 输出一个竖线,用于标记矩形框的底部
    111. std::cout << "|\n";
    112. // 如果找到目标值,则返回1,表示成功找到
    113. return 1;
    114. }
    115. // 每遍历一个节点,计数器n加1
    116. n += 1;
    117. // 将指针p移动到下一个节点
    118. p = p->next;
    119. }
    120. // 如果未找到目标值,则返回0,表示未找到
    121. return 0;
    122. }
    123. // 主函数开始
    124. int main() {
    125. // 使用当前时间作为随机数种子,保证每次运行程序时生成的随机数不同
    126. srand(time(0));
    127. // 定义常量MAX_OP为7
    128. #define MAX_OP 7
    129. // 初始化一个空的链表,头节点为nullptr
    130. Node* head = nullptr;
    131. // 循环执行MAX_OP次操作,每次插入一个随机位置的随机值节点到链表中
    132. for (int i = 0; i < MAX_OP; i++) {
    133. // 生成一个随机位置(范围为i+1,保证位置从0开始)和一个随机值(范围为0-99)
    134. int pos = rand() % (i + 1), val = rand() % 100;
    135. // 输出插入操作的信息
    136. std::cout << "insert " << val << " at " << pos << " to linklist" << std::endl;
    137. // 将新节点插入到指定位置,并更新头节点指针head
    138. head = insert(head, pos, val);
    139. // 输出当前链表的内容
    140. output_linklist(head);
    141. }
    142. // 从标准输入中读取一个整数val
    143. int val;
    144. while (std::cin >> val) {
    145. // 在链表中查找值为val的节点,如果没有找到则返回0,表示未找到
    146. if (!find(head, val)) {
    147. // 如果未找到,则输出not found信息
    148. std::cout << "not found" << std::endl;
    149. }
    150. }
    151. // 清空链表,释放内存空间
    152. clear(head);
    153. // 主函数结束,返回0表示程序正常退出
    154. return 0;
    155. }

    这段代码实现了一个简单的链表数据结构,并提供了插入、查找和输出链表的功能。

    首先,代码中定义了一些宏,其中DL被定义为3,用于表示链表节点中的整数占用的位数。STR(n)用于将一个数值表达式n转换为字符串,DIGIT_LEN_STR(n)用于计算一个整数的位数并转换为字符串。

    接下来,定义了一个结构体Node,表示链表的节点。每个节点包含一个整数数据成员data和一个指向下一个节点的指针next

    然后,定义了一个函数getNewNode(int val),用于创建一个新的节点,并初始化其数据成员为给定的值val,并将指针next初始化为nullptr

    接下来,定义了函数insert(Node* head, int pos, int val),用于在链表中插入一个新的节点。该函数首先创建一个新的节点,然后使用一个临时头节点new_head来处理插入位置。它通过循环遍历链表,找到指定位置的前一个节点,然后将新节点插入到该节点之后。最后返回更新后的链表头节点。

    接下来,定义了函数clear(Node* head),用于清空链表。该函数通过遍历链表并逐个删除节点来释放内存空间。

    接下来,定义了函数output_linklist(Node* head, int flag = 0),用于输出链表的内容。该函数首先计算链表的长度,然后依次输出每个节点的数据和指向下一个节点的箭头符号。如果flag的值为0,则在最后输出一个换行符。

    接下来,定义了函数find(Node* head, int val),用于在链表中查找指定的值。该函数遍历链表,如果找到了与给定值相等的节点,则输出该节点及其后的所有节点,并在其前面输出一个标记符号"^"和"|",然后返回1表示找到了目标值。如果遍历完整个链表都没有找到目标值,则返回0表示未找到。

    最后,在主函数中,首先使用随机数生成器初始化随机数种子,然后通过循环随机生成插入操作和输出操作。每次循环中,随机生成一个插入位置和插入的值,然后调用insert函数将新节点插入到指定位置,并输出更新后的链表内容。循环结束后,从标准输入中读取一个整数,然后调用find函数在链表中查找该整数。如果找到了目标值,则返回1;否则返回0,表示未找到。

    总结起来,这段代码实现了一个简单的链表数据结构,并提供了插入、查找和输出链表的功能。

    运行结果

  • 相关阅读:
    MATLAB:拟合与插值
    asp毕业设计——基于asp+sqlserver的工艺品销售系统设计与实现(毕业论文+程序源码)——工艺品销售系统
    单源最短路的拓展应用
    【java:牛客每日三十题总结-3】
    ESP32上实现面向对象的C++ OOP——面向对象的点灯
    Vue.js核心技术解析与uni-app跨平台实战开发学习笔记 第7章 Vue.js高级进阶 7.8 slot插槽
    Codeforces Round #835 (Div. 4) C. Advantage
    网络安全(黑客)自学
    通过CTY、VTY、TTY访问网络设备[计网实践Cisco Packet Tracer]
    C++之STL前序
  • 原文地址:https://blog.csdn.net/dsafefvf/article/details/132739812