归并排序 nO(lgn) 审核中

归并,排序,no,lgn,审核 · 浏览次数 : 0

小编点评

## Merge Sort Algorithm Explanation This code provides a detailed explanation of the merge sort algorithm and how to implement it using recursion. **Algorithm Logic:** 1. Divide the input array into two halves. 2. Recursively sort the left and right halves. 3. Merge the two sorted halves into a single sorted array. **Detailed Algorithm Steps:** - `func mergesort(arr []int, l, r int)`: - `if l >= r`: - Return if the array length is 0. - Calculate the midpoint (mid) of the array. - Recursively sort the left and right halves of the array. - `merge(arr, l, mid, r)`: - Merge the two sorted halves into a single sorted array `newArr`. - Create two temporary arrays: `arr1` for the left half and `arr2` for the right half. - Initialize a new array `newArr` to hold the merged result. - Iterate through both `arr1` and `arr2` and compare elements. - If the element from `arr1` is greater than the element from `arr2`, add it to `newArr` and increment `j` to point to the next element in `arr2`. - Otherwise, add the element from `arr1` and increment `i` to point to the next element in `arr1`. - After the merge, copy the remaining elements from `arr1` and `arr2` to `newArr`. - Copy the elements from `newArr` back to the original `arr` at the specified positions. **Application Example:** The code provides an example usage of merge sort to solve a leetcode problem. The problem is to find the number of reverse pairs in an array. ```python def merge(arr, l, mid, r): # Initialize two temporary arrays arr1 = arr[l:mid+1] arr2 = arr[mid+1:r+1] # Create a new array to store the merged result newArr = []int(0) # Initialize counters for the left and right arrays i = 0 j = 0 # Merge the two arrays element by element for i < len(arr1) and j < len(arr2): if arr1[i] > arr2[j]: newArr[k] = arr2[j] j += 1 k += 1 else: newArr[k] = arr1[i] i += 1 k += 1 # Copy the remaining elements from arr1 and arr2 to newArr if i == len(arr1): copy(newArr, arr2[j:]) else: copy(newArr, arr1[i:]) # Return the merged result return newArr ``` **Output:** ```python Output: 5 ``` This code calculates the number of reverse pairs in the given array using merge sort.

正文

大家好,我是蓝胖子,我一直相信编程是一门实践性的技术,其中算法也不例外,初学者可能往往对它可望而不可及,觉得很难,学了又忘,忘其实是由于没有真正搞懂算法的应用场景,所以我准备出一个系列,囊括我们在日常开发中常用的算法,并结合实际的应用场景,真正的感受算法的魅力。

代码已经上传github

https://github.com/HobbyBear/codelearning/tree/master/mergesort

算法原理

每每实现算法的时候,我总是倾向于用文字将算法的逻辑描述出来,当你能清晰的描述算法逻辑的时候,实现起来就是水到渠成的事情。

所以,我们接下来首先看下归并排序的算法逻辑。归并排序的时间复杂度是nO(lg n),它要求每次 将数组一分为二,被分割的数组又一分为二直至不能被分割,最后由底向上进行两两合并。你可以看到,假设数组长度是n,整个过程一共有lg n层,每一层需要对n个元素进行合并,所以时间复杂度是nO(lg n)。如下图所示:

Pasted image 20230905144638.png

合并的过程是将合并的两个有序数组的元素变成一个有序数组的过程,我们把这个过程称为merge,于是我们将 归并排序的详细步骤总结为如下的步骤,

1,将数组一分为二,形成左右子数组。

2,对左子数组进行归并排序。

3,对右子数组进行归并排序。

4,对左右子数组进行merge。

详细的merge操作我们可以在O(n)时间复杂度内完成,详细步骤可以总结如下:

1,用i表示左子数组当前遍历的元素,j表示右边子数组当前遍历的元素。

2,创建一个新数组,用于保存排好序的元素,开始遍历左右子数组,如果左右子数组都没有遍历完,则比较各自当前遍历元素的大小,将小的元素复制到新数组,然后移动小元素所在数组当前遍历的指针指向下一个遍历元素。

3,如果其中一个数组遍历完成则只需要将,没有遍历完的那个数组剩下元素全部复制到新数组即可。

实现

了解了上述详细步骤后,我们可以很容易的用递归实现上述归并排序逻辑。

// 将数组[l...r]一分为二,分别对左右数组进行排序,然后对排序好的数组进行归并  
func mergesort(arr []int, l, r int) {  
   if l >= r {  
      return  
   }  
   mid := (l + r) / 2  
   mergesort(arr, l, mid)  
   mergesort(arr, mid+1, r)  
   merge(arr, l, mid, r)  
}

merge 部分代码如下,

写算法逻辑的时候一定要注意边界条件,比如我这里定义的是闭区间,那么下面的逻辑都是按闭区间去写的。

// [l...mid] [mid+1...r]  
func merge(arr []int, l, mid, r int) {  
   arr1 := arr[l : mid+1]  
   arr2 := arr[mid+1 : r+1]  
   newArr := make([]int, r-l+1)  
   i := 0 // 当前遍历元素  
   j := 0  
   k := 0  
   for i < len(arr1) && j < len(arr2) {  
      if arr1[i] > arr2[j] {  
         newArr[k] = arr2[j]  
         j++  
         k++  
         continue  
      }  
      newArr[k] = arr1[i]  
      k++  
      i++  
   }  
   if i == len(arr1) {  
      copy(newArr[k:], arr2[j:])  
   }  
   if j == len(arr2) {  
      copy(newArr[k:], arr1[i:])  
   }  
   copy(arr[l:], newArr)  
}

应用 求解逆序对的数量

关于归并排序的一个应用,我这里用leetcode一个题举例,这个题是leetcode 的剑指 Offer 51题,求解逆序对。

剑指 Offer 51. 数组中的逆序对  
困难  
1.1K  
相关企业  
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。  
  
示例 1:  
输入: [7,5,6,4]  
输出: 5  
  
限制:  
  
0 <= 数组长度 <= 50000

这道题可以采用归并排序的思想,在merge时,得到逆序对的数量,如下,

Pasted image 20230905150954.png

merge时的两个数组是有序的,且归并排序的左右数组的相对顺序是不变的,当右边数组合并到左边数组时,如果左边的数组元素大,则说左边数组当前遍历的元素和其以后的元素都可以和右边的数组构成一个逆序对。

所以我们可以在merge的代码逻辑中添加一段累计逆序对的逻辑,如下:

func mergeCopy(arr []int, l, mid, r int, cnt *int) {  
   arr1 := arr[l : mid+1]  
   arr2 := arr[mid+1 : r+1]  
   newArr := make([]int, r-l+1)  
   i := 0 // 当前遍历元素  
   j := 0  
   k := 0  
   for i < len(arr1) && j < len(arr2) {  
      if arr1[i] > arr2[j] {  
         newArr[k] = arr2[j]  
         //  新增cnt 变量用于保存逆序对的数量
         *cnt += len(arr1) - i  
         j++  
         k++  
         continue  
      }  
      newArr[k] = arr1[i]  
      k++  
      i++  
   }  
   if i == len(arr1) {  
      copy(newArr[k:], arr2[j:])  
   }  
   if j == len(arr2) {  
      copy(newArr[k:], arr1[i:])  
   }  
   copy(arr[l:], newArr)  
}

与归并排序 nO(lgn) 审核中相似的内容:

归并排序 nO(lgn) 审核中

大家好,我是蓝胖子,我一直相信编程是一门实践性的技术,其中算法也不例外,初学者可能往往对它可望而不可及,觉得很难,学了又忘,忘其实是由于没有真正搞懂算法的应用场景,所以我准备出一个系列,囊括我们在日常开发中常用的算法,并结合实际的应用场景,真正的感受算法的魅力。 代码已经上传github https

归并排序-Python

归并排序的时间复杂度O(nlogn),空间复杂度为O(n) 首先我们先假设有两个有序数组,我们去进行一次归并 用代码实现 def merge(li: list, start: int, mid: int, end: int) : res=[] j = mid +1 while start <= mi

归并排序(递归)(NB)

博客地址:https://www.cnblogs.com/zylyehuo/ 递归思路 # _*_coding:utf-8_*_ import random def merge(li, low, mid, high): i = low j = mid + 1 ltmp = [] while i <=

C#归并排序算法

前言 归并排序是一种常见的排序算法,它采用分治法的思想,在排序过程中不断将待排序序列分割成更小的子序列,直到每个子序列中只剩下一个元素,然后将这些子序列两两合并并排序,最终得到一个有序的序列。 归并排序实现原理 将待排序序列分割成两个子序列,直到每个子序列中只有一个元素。 将相邻的两个子序列合并,并

简述几种常用的排序算法

摘要:归并排序和快速排序是两种稍微复杂的排序算法,它们用的都是分治的思想,代码都通过递归来实现,过程非常相似。理解归并排序的重点是理解递推公式和 merge() 合并函数。 本文分享自华为云社区《深入浅出八种排序算法》,作者:嵌入式视觉 。 归并排序和快速排序是两种稍微复杂的排序算法,它们用的都是分

数据结构作业(五):直接插入排序 和 归并排序

好家伙,写作业 1.直接插入排序 这是个非常简单的排序 将一串数分为有序区和无序区 然后将无序区的数一个个按照正确的顺序放到有序区 2.归并排序 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。 若将两个有序表合并成一个有序表,称为二路归并。 其中我们要解决的一个

Kafka实时数据即席查询应用与实践

Kafka中的实时数据是以Topic的概念进行分类存储,而Topic的数据是有一定时效性的,比如保存24小时、36小时、48小时等。而在定位一些实时数据的Case时,如果没有对实时数据进行历史归档,在排查问题时,没有日志追述,会很难定位是哪个环节的问题。

Pandas 使用教程 Series、DataFrame

[TOC] Pandas 一个强大的分析结构化数据的工具集,基础是 Numpy(提供高性能的矩阵运算) Pandas 可以从各种文件格式比如 CSV、JSON、SQL、Microsoft Excel 导入数据。 Pandas 可以对各种数据进行运算操作,比如归并、再成形、选择,还有数据清洗和数据加工

归约证明在密码学中的应用

在现代信息社会,密码学在保护信息安全中扮演着至关重要的角色。而归约证明(Reduction Proof)作为密码学中的一个重要工具,通过将一个问题的安全性归约为另一个已知问题的难解性,从而证明新问题的安全性。本文将详细介绍归约证明的概念、步骤及其在密码学中的应用。

分类模型的算法性能评价

一、概述 分类模型是机器学习中一种最常见的问题模型,在许多问题场景中有着广泛的运用,是模式识别问题中一种主要的实现手段。分类问题概况起来就是,对一堆高度抽象了的样本,由经验标定了每个样本所属的实际类别,由特定算法训练得到一个分类器,输入样本属性即自动计算出其所属类别,从而完成特定的识别任务。依实现原