当前位置:   article > 正文

构建有序链表,有序链表的归并,反转链表

构建有序链表,有序链表的归并,反转链表

本次将对于构建有序链表,有序链表的归并,反转链表,进行一一介绍和代码分享。

首先是一些链表中的基本的函数:

  1. Node* creatList()
  2. {
  3. Node* headNode = (Node*)malloc(sizeof(Node));
  4. assert(headNode);
  5. headNode->next = NULL;
  6. return headNode;
  7. }
  8. Node* creatNode(Datatype data)
  9. {
  10. Node* newNode = (Node*)malloc(sizeof(Node));
  11. assert(newNode);
  12. newNode->data = data;
  13. newNode->next = NULL;
  14. return newNode;
  15. }
  16. void traverseList(Node* headNode)
  17. {
  18. Node* posNode = headNode->next;
  19. while (posNode != NULL)
  20. {
  21. printf("%d ", posNode->data);
  22. posNode = posNode->next;
  23. }
  24. }

这里很基本,如果理解有困难,请从头学习链表。

以下是构建有序链表,也就是找到符合顺序的位置进行节点插入:

  1. //构建有序链表:和构建顺序表一样,需要找到符合顺序的位置,然后插入元素
  2. //核心是找到第一个比它大的节点,放到这个节点之前(双节点遍历)
  3. void insertData(Node* headNode, Datatype data)
  4. {
  5. Node* newNode = creatNode(data);
  6. Node* posNode = headNode->next;
  7. Node* preNode = headNode;
  8. //assert(posNode);
  9. //当前面节点的数据小于data的时候,继续向后走
  10. while (posNode!= NULL && posNode->data <= data)
  11. {
  12. posNode = posNode->next;
  13. preNode = preNode->next;
  14. }
  15. //特殊的情况分析:(短路现象)
  16. //pos在第一个节点,第一个节点为空,那么说明只有表头,连接表头和newNode
  17. if (posNode == NULL&&posNode == headNode->next)
  18. {
  19. headNode->next= newNode;
  20. }
  21. //pos不在第一个节点,但是pos指向空,
  22. //pos指向最后一个节点的后面一个,也就是还有没有找到大于data的:
  23. // 说明没有大于data的节点,所以将data与最后连接即可
  24. else if (posNode == NULL && posNode != headNode->next)
  25. {
  26. preNode->next = newNode;
  27. }
  28. //找到了位置,插入在pos的前面
  29. else
  30. {
  31. newNode->next = posNode;
  32. preNode->next = newNode;
  33. }
  34. }

这个过程和顺序表的构建流程基本相同,比较简单,所以不做过多解释。

接下来是单链表的翻转:

  1. void reverseList(Node* headNode)
  2. {
  3. //对于1个表头,1个节点;1个表头,2个节点的链表不需要进行翻转
  4. if (headNode->next == NULL || headNode->next->next == NULL)
  5. {
  6. return;
  7. }
  8. Node* posNode = headNode->next;
  9. Node* preNode = NULL;
  10. Node* sucNode = headNode->next->next;
  11. while (sucNode != NULL)
  12. {
  13. //指向改变
  14. posNode->next = preNode;
  15. //整体向后移动
  16. preNode = posNode;
  17. posNode = sucNode;
  18. sucNode = sucNode->next;
  19. }
  20. //最后一步改变指向方向
  21. posNode->next = preNode;
  22. //将表头与完成反转的第一个节点相连接
  23. headNode->next = posNode;
  24. }

以下是逐步的过程模拟:结合代码中的注释和过程一一对应更容易理解,其中preNode,sucNode分别是posNode的前驱和后继节点。

示例

假设我们有以下的单链表:

headNode -> 1 -> 2 -> 3 -> 4 -> NULL

我们希望反转后得到:

headNode -> 4 -> 3 -> 2 -> 1 -> NULL

分析执行过程

  1. 初始化指针:
    • posNode 指向第一个元素(1)。
    • preNode 为 NULL(因为没有前驱节点)。
    • sucNode 指向第二个元素(2)。
  2. 进入循环,当 sucNode 不为 NULL 时:
    • 改变 posNode(当前节点)的 next 指针,使其指向前驱节点 preNode
    • 更新 preNode 为当前的 posNode
    • 更新 posNode 为当前的 sucNode
    • 更新 sucNode 为 posNode 的下一个节点。

这个过程会一直持续到 sucNode 为 NULL,即到达链表的末尾。

  1. 在循环结束后,执行以下操作:
    • 将最后一个节点(posNode)的 next 指针指向 preNode
    • 将头节点的 next 指针指向反转后的第一个节点(posNode)。

最后,两个有序链表的归并:

  1. //有序链表的归并:
  2. void mergeList(Node* newHeadNode, Node* head1, Node* head2)
  3. {
  4. Node* up = head1->next;
  5. Node* down = head2->next;
  6. Node* temp = newHeadNode;
  7. assert(up && down);
  8. while (up != NULL && down != NULL)
  9. {
  10. if (up->data < down->data)
  11. {
  12. temp->next= up;
  13. up = up->next;
  14. }
  15. else
  16. {
  17. temp->next = down;
  18. down = down->next;
  19. }
  20. temp = temp->next;
  21. }
  22. //up结尾,down没结尾
  23. if (up == NULL && down != NULL)
  24. {
  25. temp->next = down;
  26. }
  27. //down结尾,up没结尾
  28. else if (up != NULL && down == NULL)
  29. {
  30. temp->next = up;
  31. }
  32. //没有两个同时结尾的情况
  33. }

示例和分析执行过程:

假设我们有以下两个有序链表:

head1: 1 -> 3 -> 5
head2: 2 -> 4 -> 6

调用 mergeList(newHeadNode, head1, head2); 后,我们希望得到以下合并后的链表:

newHeadNode -> 1 -> 2 -> 3 -> 4 -> 5 -> 6

执行过程:

  1. up 指向 1down 指向 2temp 指向 newHeadNode
  2. 因为 1 < 2,所以 temp->next = up;,然后 up 移动到 3temp 移动到 1
  3. 现在 up 指向 3down 指向 2
  4. 因为 2 < 3,所以 temp->next = down;,然后 down 移动到 4temp 移动到 2
  5. 重复这个过程,直到 up 或 down 为 NULL
  6. 在本例中,当 up 指向 5 且 down 指向 4 时,因为 4 < 5down 指向的节点会被插入到新链表中。
  7. 当 down 遍历到 NULL 时,up 还有节点 5 和 6。因此,将 up 指向的剩余链表直接连接到新链表的末尾。

对于链表的归并,代码虽然简单,但要理解其中的流程是极为关键的,本次的分享结束,希望对你有帮助。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/477913
推荐阅读
相关标签
  

闽ICP备14008679号