排序(四)归并排序 c/c++与python实现

归并排序(Merge Sort)

归并,即将两个或两个以上的有序表组成一个新的有序表。

2-路归并排序的基本思想:将序列视为n个组,将这些组两两归并归并为n/2个组,然后将这些组再两两归并,生成n/4个组,以此类推,直到只剩下一个组为止。

归并排序使用的就是分治思想,即先把序列从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分归并在一起,这样整个序列就都有序了。
在这里插入图片描述
关于递归与分治:

  • 分治是一种解决问题的处理思想,而递归是一种编程技巧。
  • 分治算法一般都是用递归来实现的。
#include <stdio.h>
#include <stdlib.h>
//	归并排序递归c/c++实现
/**
 * Author: gamilian
*/
const int maxn =100;
//将数组a的[L1,R1]与[L2,R2]区间合并为有序区间(此处L2即为R1+1)
void merge(int a[], int L1, int R1, int L2, int R2){
	int i = L1, j = L2;				
	int temp[maxn], index = 0;		
	while(i <= R1 && j <= R2){
		if(a[i] <= a[j])
			temp[index++] = a[i++];//将a[i]加入序列temp
		else	
			temp[index++] = a [j++];
	}
	while(i <= R1)
		temp[index++] = a[i++];//将[L1,R1]的剩余元素加入序列temp
	while(j <= R2)
		temp[index++] = a[j++];//将[L2,R2]的剩余元素加入序列temp 
	
	for(i = 0; i < index; i++){
		a[L1 + i] = temp[i];//将合并后的序列赋值回数组A
	}
}
void merge_sort_between(int a[], int left, int right){
	if (left < right){
	int mid = left + (right - left) / 2;
	merge_sort_between(a, left, mid);		//左区间归并排序
	merge_sort_between(a, mid + 1, right);	//右区间归并排序
	merge(a, left, mid, mid + 1, right);
	}	//将左、右区间归并
}
void merge_sort(int a[], int n){
	merge_sort_between(a, 0 ,n - 1);
}
//	归并排序非递归c/c++实现
/**
 * Author: gamilian
*/
#define min(x, y) (x) < (y) ? (x) : (y)
void merge_sort(int a[], int n){
	for(int step = 2; step / 2 <= n; step *= 2){	//step为组内元素个数,step/2为左子区间元素的个数
		for(int i = 0; i < n; i += step){			//每step个元素一组,组内前step/2个元素与后step/2个元素归并
			int mid = i + step / 2 - 1;
			if (mid + 1 < n){	//右区间存在则合并
				merge(a, i ,mid, mid + 1, min(i + step - 1 , n - 1)); 
			}
		}
	}
}
#	归并排序递归python实现
"""
    Author: gamilian
"""
from typing import List
def merge_sort(a: List[int]):
    merge_sort_between(a, 0, len(a) - 1)
    
# 对[left, right]区间内的元素归并排序
def merge_sort_between(a: List[int], left: int, right: int):
    if left < right:
        mid = left + (right - left) // 2
        #   左区间归并排序
        merge_sort_between(a, left, mid) 
        #   右区间归并排序
        merge_sort_between(a, mid + 1, right)
        #   将左、右区间归并
        merge(a, left, mid, mid + 1, right)

def merge(a: List[int], L1: int, R1: int, L2: int, R2: int):
    # 默认L2 = R1 + 1
    i, j = L1, L2
    tmp = []
    while i <= R1 and j <= R2:
        if a[i] <= a[j]:
            tmp.append(a[i])
            i += 1
        else:
            tmp.append(a[j])
            j += 1
    start = i if i <= R1 else j
    end = R1 if i <= R1 else R2
    tmp.extend(a[start:end + 1])
    length = len(tmp)
    a[L1:L1 + length] = tmp
#	归并排序非递归python实现
"""
    Author: gamilian
"""
from typing import List
def merge_sort(a: List[int]):
    length = len(a)
    step = 2
    for step in range(2, length * 4, 2):
        for i in range(0, length, step):
            mid = i + step // 2 - 1
            if mid + 1 < length:
                merge(a, i, mid, mid + 1, min(i + step - 1 , length - 1))

算法的稳定性:值相同的元素,在归并前后的先后顺序不变。所以,归并排序是一个稳定的排序算法

空间复杂度 :在归并两个有序序列为一个有序序列时,需要借助额外的存储空间。尽管每次归并操作都需要申请额外的内存空间,但在合并完成之后,临时开辟的内存空间就被释放掉了。在任意时刻,CPU 只会有一个函数在执行,也就只会有一个临时的内存空间在使用。临时内存空间最大也不会超过 n 个数据的大小,所以空间复杂度是 O(n)

时间复杂度:归并排序采用分治的思想:将一个大问题a分为多个子问题b、c。如果我们定义求解问题 a 的时间是 T(n),求解问题 b、c 的时间分别是 T(n/2) 和 T(n/2),而merge() 函数合并两个有序子数组的时间复杂度是 O(n)。那我们就可以得到这样的递推关系式:

T(1) = C;		// n = 1时,只需要常量级的执行时间,所以表示为C。
T(n) = 2 * T(n/2)  + n;	//n > 1

故:

T(n) = 2*T(n/2) + n 
	 = 2*(2*T(n/4) + n/2) + n 
   	 = 4*T(n/4) + 2*n 
   	 = 4*(2*T(n/8) + n/4) + 2*n 
   	 = 8*T(n/8) + 3*n = 8*(2*T(n/16) + n/8) + 3*n 
   	 = 16*T(n/16) + 4*n ...... 
   	 = 2^k * T(n/2^k) + k * n ......

当 T(n/2^k) =T(1) 时,也就是 n/2^k=1,我们得到 k=log2n 。T(n)=Cn+nlog2n 。

归并排序的执行效率与要排序的原始数组的有序程度无关,所以其时间复杂度是非常稳定的,不管是最好情况、最坏情况,还是平均情况,时间复杂度都是 O(nlogn)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常抱歉,我误解了您的问题。以下是使用C++语言实现的包含所有排序算法的代码: ```c++ #include <iostream> using namespace std; // 冒泡排序 void bubble_sort(int arr[], int n) { for (int i = 0; i < n-1; i++) { for (int j = 0; j < n-i-1; j++) { if (arr[j] > arr[j+1]) { swap(arr[j], arr[j+1]); } } } } // 选择排序 void selection_sort(int arr[], int n) { for (int i = 0; i < n-1; i++) { int min_idx = i; for (int j = i+1; j < n; j++) { if (arr[j] < arr[min_idx]) { min_idx = j; } } swap(arr[i], arr[min_idx]); } } // 插入排序 void insertion_sort(int arr[], int n) { for (int i = 1; i < n; i++) { int key = arr[i]; int j = i - 1; while (j >= 0 && arr[j] > key) { arr[j+1] = arr[j]; j--; } arr[j+1] = key; } } // 快速排序 int partition(int arr[], int low, int high) { int pivot = arr[high]; int i = low - 1; for (int j = low; j <= high-1; j++) { if (arr[j] < pivot) { i++; swap(arr[i], arr[j]); } } swap(arr[i+1], arr[high]); return i+1; } void quick_sort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); quick_sort(arr, low, pi-1); quick_sort(arr, pi+1, high); } } // 归并排序 void merge(int arr[], int l, int m, int r) { int n1 = m - l + 1; int n2 = r - m; int L[n1], R[n2]; for (int i = 0; i < n1; i++) { L[i] = arr[l+i]; } for (int j = 0; j < n2; j++) { R[j] = arr[m+1+j]; } int i = 0; int j = 0; int k = l; while (i < n1 && j < n2) { if (L[i] <= R[j]) { arr[k] = L[i]; i++; } else { arr[k] = R[j]; j++; } k++; } while (i < n1) { arr[k] = L[i]; i++; k++; } while (j < n2) { arr[k] = R[j]; j++; k++; } } void merge_sort(int arr[], int l, int r) { if (l < r) { int m = l + (r-l)/2; merge_sort(arr, l, m); merge_sort(arr, m+1, r); merge(arr, l, m, r); } } int main() { int arr[] = {64, 34, 25, 12, 22, 11, 90}; int n = sizeof(arr) / sizeof(arr[0]); bubble_sort(arr, n); cout << "冒泡排序后的数组:"; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; selection_sort(arr, n); cout << "选择排序后的数组:"; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; insertion_sort(arr, n); cout << "插入排序后的数组:"; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; quick_sort(arr, 0, n-1); cout << "快速排序后的数组:"; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; merge_sort(arr, 0, n-1); cout << "归并排序后的数组:"; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; } ``` 您可以根据需要调用这些排序函数,例如: ```c++ int arr[] = {64, 34, 25, 12, 22, 11, 90}; int n = sizeof(arr) / sizeof(arr[0]); bubble_sort(arr, n); cout << "冒泡排序后的数组:"; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; ``` 输出结果为: ``` 冒泡排序后的数组:11 12 22 25 34 64 90 ``` 希望这次能够真正地回答到您的问题!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值