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

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

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

令 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)

目录
相关文章
|
存储 算法 Perl
数据结构实验之链表
本实验旨在掌握线性表中元素的前驱、后续概念及链表的建立、插入、删除等算法,并分析时间复杂度,理解链表特点。实验内容包括循环链表应用(约瑟夫回环问题)、删除单链表中重复节点及双向循环链表的设计与实现。通过编程实践,加深对链表数据结构的理解和应用能力。
250 4
|
11月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
429 30
|
11月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
584 25
|
12月前
|
搜索推荐 C语言
数据结构(C语言)之对归并排序的介绍与理解
归并排序是一种基于分治策略的排序算法,通过递归将数组不断分割为子数组,直到每个子数组仅剩一个元素,再逐步合并这些有序的子数组以得到最终的有序数组。递归版本中,每次分割区间为[left, mid]和[mid+1, right],确保每两个区间内数据有序后进行合并。非递归版本则通过逐步增加gap值(初始为1),先对单个元素排序,再逐步扩大到更大的区间进行合并,直至整个数组有序。归并排序的时间复杂度为O(n*logn),空间复杂度为O(n),且具有稳定性,适用于普通排序及大文件排序场景。
|
存储 人工智能 算法
【C++数据结构——内排序】二路归并排序(头歌实践教学平台习题)【合集】
本关任务是实现二路归并算法,即将两个有序数组合并为一个有序数组。主要内容包括: - **任务描述**:实现二路归并算法。 - **相关知识**: - 二路归并算法的基本概念。 - 算法步骤:通过比较两个有序数组的元素,依次将较小的元素放入新数组中。 - 代码示例(以 C++ 为例)。 - 时间复杂度为 O(m+n),空间复杂度为 O(m+n)。 - **测试说明**:平台会对你编写的代码进行测试,提供输入和输出示例。 - **通关代码**:提供了完整的 C++ 实现代码。 - **测试结果**:展示代码运行后的排序结果。 开始你的任务吧,祝你成功!
404 10
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
579 5
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
425 5
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表

热门文章

最新文章