数据结构单链表之链表的归并排序 | 第十一套

简介: 数据结构单链表之链表的归并排序 | 第十一套

合并排序通常用于对链表进行排序。链表缓慢的随机访问性能使得其他一些算法(如快速排序)表现不佳,而其他算法(如堆排序)则完全不可能。

令 head 为链表的第一个要排序的节点,headRef 为 head 的指针。请注意,我们需要在 MergeSort() 中引用 head,因为下面的实现更改了下一个链接以对链表进行排序(不是节点上的数据),因此如果原始头部的数据不是链表中的最小值。

合并排序(headRef)
1)如果head为NULL或链表中只有一个元素 
    然后返回。
2)否则将链表分成两半。  
      FrontBackSplit(head, &a, &b); /* a 和 b 是两半 */
3) 将 a 和 b 的两半排序。
      归并排序(一);
      归并排序(b);
4) 合并已排序的 a 和 b(使用此处讨论的 SortedMerge() )
   并使用 headRef 更新头指针。
     *headRef = SortedMerge(a, b);
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
  int data;
  Node* next;
};
Node* SortedMerge(Node* a, Node* b);
void FrontBackSplit(Node* source,
          Node** frontRef, Node** backRef);
void MergeSort(Node** headRef)
{
  Node* head = *headRef;
  Node* a;
  Node* b;
  if ((head == NULL) || (head->next == NULL)) {
    return;
  }
  FrontBackSplit(head, &a, &b);
  MergeSort(&a);
  MergeSort(&b);
  *headRef = SortedMerge(a, b);
}
Node* SortedMerge(Node* a, Node* b)
{
  Node* result = NULL;
  if (a == NULL)
    return (b);
  else if (b == NULL)
    return (a);
  if (a->data <= b->data) {
    result = a;
    result->next = SortedMerge(a->next, b);
  }
  else {
    result = b;
    result->next = SortedMerge(a, b->next);
  }
  return (result);
}
void FrontBackSplit(Node* source,
          Node** frontRef, Node** backRef)
{
  Node* fast;
  Node* slow;
  slow = source;
  fast = source->next;
  while (fast != NULL) {
    fast = fast->next;
    if (fast != NULL) {
      slow = slow->next;
      fast = fast->next;
    }
  }
  *frontRef = source;
  *backRef = slow->next;
  slow->next = NULL;
}
void printList(Node* node)
{
  while (node != NULL) {
    cout << node->data << " ";
    node = node->next;
  }
}
void push(Node** head_ref, int new_data)
{
  Node* new_node = new Node();
  new_node->data = new_data;
  new_node->next = (*head_ref);
  (*head_ref) = new_node;
}
int main()
{
  Node* res = NULL;
  Node* a = NULL;
  push(&a, 15);
  push(&a, 10);
  push(&a, 5);
  push(&a, 20);
  push(&a, 3);
  push(&a, 2);
  MergeSort(&a);
  cout << "Sorted Linked List is: \n";
  printList(a);
  return 0;
}

输出:

Sorted Linked List is: 
2 3 5 10 15 20

时间复杂度:  O(n*log n)\

空间复杂度:  O(n*log n)

方法 2: 这种方法更简单,使用 log n 空间。

合并排序():

  1. 如果链表的大小为 1,则返回头部
  2. 使用乌龟和兔子的方法找到中间
  3. 将 mid 的 next 存储在 head2 中,即右子链表。
  4. 现在使下一个中点为空。
  5. 对左右子链表递归调用mergeSort(),存储左右子链表的新头。
  6. 给定左右子链表的新头的参数调用 merge() 并存储合并后返回的最终头。
  7. 返回合并链表的最终头。

合并(头1,头2):

  1. 取一个指针 say merge 将合并的列表存储在其中并在其中存储一个虚拟节点。
  2. 取一个指针 temp 并为其分配合并。
  3. 如果 head1 的数据小于 head2 的数据,则将 head1 存储在 temp 的 next 并将 head1 移动到 head1 的 next。
  4. 否则将 head2 存储在 temp 的下一个并将 head2 移动到 head2 的下一个。
  5. 将 temp 移动到 temp 的下一个。
  6. 重复步骤 3、4 和 5,直到 head1 不等于 null 且 head2 不等于 null。
  7. 现在将第一个或第二个链表的任何剩余节点添加到合并的链表中。
  8. 返回合并的下一个(这将忽略虚拟并返回最终合并链表的头部)
#include<iostream>
using namespace std;
struct Node{
  int data;
  Node *next;
};
void insert(int x,Node **head) {
  if(*head == NULL){
    *head = new Node;
    (*head)->data = x;
    (*head)->next = NULL;
    return;
  }
  Node *temp = new Node;
  temp->data = (*head)->data;
  temp->next = (*head)->next;
  (*head)->data=x;
  (*head)->next=temp;
}
void print(Node *head) {
  Node *temp=head;
  while(temp!=NULL) {
    cout<<temp->data<<" ";
    temp = temp->next;
  }
}
Node *merge(Node *firstNode,Node *secondNode) {
  Node *merged = new Node;
  Node *temp = new Node;
  merged = temp;
  while(firstNode != NULL && secondNode != NULL) {
    if(firstNode->data<=secondNode->data) {
      temp->next = firstNode;
      firstNode = firstNode->next;
    }
    else {
      temp->next = secondNode;
      secondNode = secondNode->next;
    }
    temp = temp->next;
  }
  while(firstNode!=NULL) {
    temp->next = firstNode;
    firstNode = firstNode->next;
    temp = temp->next;
  }
  while(secondNode!=NULL) {
    temp->next = secondNode;
    secondNode = secondNode->next;
    temp = temp->next;
  }
  return merged->next;
}
Node *middle(Node *head) {
  Node *slow = head;
  Node *fast = head->next;
  while(slow->next != NULL && (fast!=NULL && fast->next!=NULL)) {
    slow = slow->next;
    fast = fast->next->next;
  }
  return slow;
}
Node *sort(Node *head){
  if(head->next == NULL) {
    return head;
  }
  Node *mid = new Node;
  Node *head2 = new Node;
  mid = middle(head);
  head2 = mid->next;
  mid->next = NULL;
  Node *finalhead = merge(sort(head),sort(head2));
  return finalhead;
}
int main(void) {
  Node *head = NULL;
  int n[]={7,10,5,20,3,2};
  for(int i=0;i<6;i++) {
    insert(n[i],&head); 
  }
cout<<"\nSorted Linked List is: \n";
  print(sort(head));  
  return 0;
}

输出:

Sorted Linked List is: 
2 3 5 7 10 20 

时间复杂度:O(n*log n)

空间复杂度:  O(log n)

目录
相关文章
|
20天前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
18 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
1天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1天前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
15天前
|
存储
[数据结构] -- 单链表
[数据结构] -- 单链表
19 1
|
20天前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
14 1
|
14天前
|
存储
[数据结构] -- 双向循环链表
[数据结构] -- 双向循环链表
16 0
|
14天前
|
存储
数据结构(单链表)
数据结构(单链表)
9 0
|
20天前
|
存储
探索数据结构:便捷的双向链表
探索数据结构:便捷的双向链表
|
20天前
|
存储
探索数据结构:单链表的实践和应用
探索数据结构:单链表的实践和应用
|
20天前
|
算法 Java
数据结构与算法学习六:单向环形链表应用实例的约瑟夫环问题
这篇文章通过单向环形链表的应用实例,详细讲解了约瑟夫环问题的解决方案,并提供了Java代码实现。
14 0