归并排序汇总

本文详细阐述了C++中归并排序算法的基本原理,并提供了两种优化方案,第一种采用局部变量减少内存分配,空间复杂度为O(N);第二种通过循环换位合并算法,实现O(1)空间复杂度的归并排序。最后,通过实例演示了如何在有限空间内高效完成排序任务。

1.具体原理就不过多介绍了,先把C++程序设计上面的代码放上来

#include <iostream>
using namespace std;

void arraycopy(int source[], int sourceStartIndex, int target[], int targetStartIndex, int length);
void merge(int list1[], int list1Length, int list2[], int list2Length, int temp[]);
void mergeSort(int list[], int arraySize)
{
	if (arraySize > 1)
	{
		int* firstHalf = new int[arraySize / 2];
		arraycopy(list, 0, firstHalf, 0, arraySize/2);
		mergeSort(firstHalf, arraySize/2);

		int secondHalfLength = arraySize - arraySize/2;
		int* secondHalf = new int[secondHalfLength];
		arraycopy(list, arraySize/2, secondHalf, 0, secondHalfLength);
		mergeSort(secondHalf, secondHalfLength);

		int* temp = new int[arraySize];
		merge(firstHalf, arraySize/2, secondHalf, secondHalfLength, temp);
		arraycopy(temp, 0, list, 0, arraySize);

		delete[]temp; 
		delete[]secondHalf;
		delete[]firstHalf;
	}
}

void arraycopy(int source[], int sourceStartIndex, int target[], int targetStartIndex, int length)
{
	for (int i = 0; i < length; i++)
	{
		target[targetStartIndex++] = source[sourceStartIndex++];
	}
}

void merge(int list1[], int list1Length, int list2[], int list2Length, int temp[])
{
	int i = 0, j = 0, k = 0;
	while (i < list1Length && j < list2Length)
	{
		if (list1[i] < list2[j])
		{
			temp[k++] = list1[i++];
		}
		else 
		{
			temp[k++] = list2[j++];
		}
	}

	while (i < list1Length)
	{
		temp[k++] = list1[i++];
	}

	while (j < list2Length)
	{
		temp[k++] = list2[j++];
	}
}

int main()
{
	int p[] = {9, 6, 4, 5, 2, 3, 1, 7, 8, 0};
	int len = 10;
	mergeSort(p, len);
	for (int i = 0; i < len; i++)
	{
		cout<<p[i]<<" ";
	}
}
分析:这种情况下,个人觉得空间复杂度会比较大每一层都要使用new,总共logN层,空间复杂度应为O(NlogN)。

2.放上来一种设定全局变量的方法,从而使得空间复杂度为O(N)

#include <iostream>
using namespace std;

int s1[10] = {9, 6, 4, 5, 2, 3, 1, 7, 8, 0};
int s2[10];	//原数组为s1,临时数组为s2。

void merge(int low, int mid, int high);
void mergeSort(int firstIndex, int secondIndex)
{
	if (firstIndex < secondIndex)
	{
		int mid = (firstIndex+secondIndex)/2;
		mergeSort(firstIndex, mid);
		mergeSort(mid+1, secondIndex);
		merge(firstIndex, mid, secondIndex);
	}
}

void merge(int low, int mid, int high)
{
	int i = low, j = mid+1, k = low;
	while(i <= mid && j <= high)
	{
		if (s1[i] < s1[j])
		{
			s2[k++] = s1[i++];
		}
		else
		{
			s2[k++] = s1[j++];
		}
	}

	while (i <= mid)
	{
		s2[k++] = s1[i++];
	}

	while (j <= high)
	{
		s2[k++] = s1[j++];
	}
	for (int l = low; l <= high; l++)
	{
		s1[l] = s2[l];	//这个for循环不能忘,因为s2会被不断地冲洗掉!
	}
}

int main()
{
	mergeSort(0, 9);
	for (int i = 0; i < 10; i++)
	{
		cout<<s2[i]<<" ";
	}
}
3.O(1)空间合并算法

问题描述:设子数组:a[0:k-1]和a[k:n-1]已排好顺序(0 <=k<=n-1)。试设计一个合并这2个子数组为排好序的数组a[0:n-1]的算法。要求算法在最坏情况下所用的计算时间为O(n),且只用到O(1)的辅助空间。

我们用循环换位合并算法:


图中红色部分为每一步需要向左循环的数组范围,其实就是讲上面的一排数插入到下面中。

#include <iostream>
using namespace std;

int binarySearch(int list[], int key, int low, int high)
{
	int mid;
	while(low <= high)
	{
		mid = (low + high)/2;
		if (key == list[mid])
			return mid;
		else if(key > list[mid])
			low = mid + 1;
		else
			high = mid - 1;
	}
	if (key > list[mid])
	{
		return mid+1;
	}
	else 
		return mid;
}

void leftShift(int list[], int low, int high)
{
	int temp = list[low];
	for (int i = low; i < high; i++)
	{
		list[i] = list[i+1];
	}
	list[high] = temp;
}

void merge(int list[], int k, int len)
{
	int firstLow = 0;
	int secondLow = k, secondHigh = len-1;
	while (firstLow < secondLow)
	{
		int pos = binarySearch(list, list[firstLow], secondLow, secondHigh);
		leftShift(list, firstLow, pos-1);
		secondLow--;
	}
}

int main()
{
	int list[] = {1, 3, 5, 7, 2, 4, 6, 8};
	int k = 4, len = 8;
	merge(list, k, len);
	for (int i = 0; i < len; i++)
	{
		cout<<list[i]<<" ";
	}
}




### Java 实现归并排序的图解及可视化教程 #### 一、归并排序简介 归并排序是一种基于分治法的高效稳定排序算法。该算法将待排序序列分为若干子序列,分别对这些子序列进行排序;再依次合已有序的子序列,最终得到完全有序的序列。 #### 二、具体操作流程 1. **分解**:把长度为n的输入序列分成两个大致相等的子序列; 2. **解决**:递归地对这两个子序列调用归并排序函数,直到每个子序列只剩下一个元素为止; 3. **合**:将已经排好序的子序列逐步合成更大的有序序列。 #### 三、图示过程展示 假设有一个无序数组`{8, 4, 5, 7, 1, 3, 6, 2}`需要被排序: - 初始状态: - 数组未经过任何处理 `{8, 4, 5, 7, 1, 3, 6, 2}` - 经过分割后的第一次迭代: - 左半边分割结果 `[8, 4], [5, 7]` - 右半边分割结果 `[1, 3], [6, 2]` - 对每一对相邻的小数组执行内部排序后继续拆分: - 接下来会形成更小规模的数据集 `[[8],[4]], [[5],[7]]`, `[[1],[3]], [[6],[2]]` - 当不能再进一步细分时开始回溯组合: - 合最底层的结果获得新的局部有序集合 `[(4,8)], [(5,7)]`, `[(1,3)], [(2,6)]` - 将上述四个部分再次配对比较大小完成新一轮融合: - 得到更大范围内的顺序排列 `[(4,5,7,8)], [(1,2,3,6)]` - 执行最后一次汇总动作即完成了整个列表的整体升序调整: - 结果变为 `(1,2,3,4,5,6,7,8)` 完全满足预期目标[^1] #### 四、代码实现样例 以下是使用Java编的简单版本归并排序程序: ```java public class MergeSort { private static void merge(int[] arr, int l, int m, int r){ // 创建临时辅助存储空间用于保存左右两侧数据副本 int n1 = m - l + 1; int n2 = r - m; /* 下标从0开始 */ int L[] = new int[n1]; int R[] = new int[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, 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++; } } private static void sort(int[] arr, int l, int r){ if (l < r){ int m = (l+r)/2; // 分别针对前后两段实施相同逻辑直至触底反弹 sort(arr, l, m); sort(arr ,m+1, r); // 随着递归返回上层节点逐渐拼接起来成为完整的有序表列 merge(arr, l, m, r); } } public static void main(String args[]){ int arr[] = {8, 4, 5, 7, 1, 3, 6, 2}; System.out.println("原始数组:"); printArray(arr); sort(arr, 0, arr.length-1); System.out.println("\n排序之后:"); printArray(arr); } /** 辅助打印功能方便观察变化情况*/ static void printArray(int arr[]){ int n = arr.length; for (int i=0; i<n; ++i) System.out.print(arr[i] + " "); System.out.println(); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值