java归并排序算法中变量left是什么意思

转自;http://flyingcat8/1281026
前面的三种排序算法(冒泡排序,选择排序,插入排序)在平均情况下均为O(n^2)复杂度,在处理较大数据的时候比较吃力。现在来说说相对快速一些的算法,例如下面的归并排序。
算法概述/思路
归并排序是基于一种被称为“分治”(divide and conquer)的策略。其基本思路是这样的:
1.对于两个有序的数组,要将其合并为一个有序数组,我们可以很容易地写出如下代码:
public void merge(int[] a, int[] b, int[] c){
&&&&int i=0,j=0,k=0;
&&&&while (i&=a.length && j&=b.length){
&&&&&&&&if (a[i]&=b[i]){
&&&&&&&&&&&&c[k++]=a[i++];
&&&&&&&&else{
&&&&&&&&&&&&c[k++]=b[j++];
&&&&while (i&=a.length){
&&&&&&&&c[k++]=a[i++];
&&&&while (j&=b.length){
&&&&&&&&c[k++]=b[j++];
容易看出,这样的合并算法是高效的,其时间复杂度可达到O(n)。
2.假如有一个无序数组需要排序,但它的两个完全划分的子数组A和B分别有序,借助上述代码,我们也可以很容易实现;
3.那么,如果A,B无序,怎么办呢?可以把它们再分成更小的数组。
4.如此一直划分到最小,每个子数组都只有一个元素,则可以视为有序数组。
5.从这些最小的数组开始,逆着上面的步骤合并回去,整个数组就排好了。
总而言之,归并排序就是使用递归,先分解数组为子数组,再合并数组。
下面是归并排序的示意图(图片来自维基百科):
&&&&public static void mergeSort(int[] arr){
&&&&&&&&int[] temp =new int[arr.length];
&&&&&&&&internalMergeSort(arr, temp, 0, arr.length-1);
&&&&private static void internalMergeSort(int[] a, int[] b, int left, int right){
&&&&&&&&if (left&right){
&&&&&&&&&&&&int middle = (left+right)/2;
&&&&&&&&&&&&internalMergeSort(a, b, left, middle);&&&&&&&&&
&&&&&&&&&&&&internalMergeSort(a, b, middle+1, right);&&&&&&
&&&&&&&&&&&&mergeSortedArray(a, b, left, middle, right);&&&
&&&&private static void mergeSortedArray(int arr[], int temp[], int left, int middle, int right){
&&&&&&&&int i=&&&&&
&&&&&&&&int j=middle+1;
&&&&&&&&int k=0;
&&&&&&&&while ( i&=middle && j&=right){
&&&&&&&&&&&&if (arr[i] &=arr[j]){
&&&&&&&&&&&&&&&&temp[k++] = arr[i++];
&&&&&&&&&&&&}
&&&&&&&&&&&&else{
&&&&&&&&&&&&&&&&temp[k++] = arr[j++];
&&&&&&&&&&&&}
&&&&&&&&while (i &=middle){
&&&&&&&&&&&&temp[k++] = arr[i++];
&&&&&&&&while ( j&=right){
&&&&&&&&&&&&temp[k++] = arr[j++];
&&&&&&&&for (i=0; i&k; ++i){
&&&&&&&&&&&&arr[left+i] = temp[i];
需要说明的是,在合并数组的时候需要一个temp数组。我们当然有足够的理由在每次调用的时候重新new一个数组(例如,减少一个参数),但是,注意到多次的创建数组对象会造成额外的开销,我们可以在开始就创建一个足够大的数组(等于原数组长度就行),以后都使用这个数组。实际上,上面的代码就是这么写的。
算法性能/复杂度
归并排序的效率是很高的,由于递归划分为子序列只需要logN复杂度,而合并每两个子序列需要大约2n次赋值,为O(n)复杂度,因此,只需要简单相乘即可得到归并排序的时间复杂度
O(㏒n)。并且由于归并算法是固定的,不受输入数据影响,所以它在最好、最坏、平均情况下表现几乎相同,均为O(㏒n)。
但是,归并排序最大的缺陷在于其空间复杂度。从上面的代码可以看到,在合并子数组的时候需要一个辅助数组,然后再把这个数据拷贝回原数组。所以,归并排序的空间复杂度(额外空间)为O(n)。可不可以省略这个数组呢?不行!如果取消辅助数组而又要保证原来的数组中数据不被覆盖,那就必须要在数组中花费大量时间来移动数据。不仅容易出错,还降低了效率。因此这个辅助空间是少不掉的。
算法稳定性
因为我们在遇到相等的数据的时候必然是按顺序“抄写”到辅助数组上的,所以,归并排序同样是稳定算法。
算法适用场景
归并排序在数据量比较大的时候也有较为出色的表现(效率上),但是,其空间复杂度O(n)使得在数据量特别大的时候(例如,1千万数据)几乎不可接受。而且,考虑到有的机器内存本身就比较小,因此,采用归并排序一定要注意。
阅读(...) 评论()java中归并排序比快速排序快吗? - 知乎43被浏览6145分享邀请回答12 条评论分享收藏感谢收起拒绝访问 |
| 百度云加速
请打开cookies.
此网站 () 的管理员禁止了您的访问。原因是您的访问包含了非浏览器特征(39d29fa2e10643b3-ua98).
重新安装浏览器,或使用别的浏览器归并排序原理及Java实现 - 怕什么真理无穷, 进一寸有一寸的欢喜 - CSDN博客
归并排序原理及Java实现
算法及数据结构
& & 归并排序是基于归并操作的一种效率较高的排序算法,同快速排序一样,归并排序也是分治法的一种应用。其时间复杂度为:O(nlogn),最好和最坏情况下都是O(nlogn)。空间复杂度为O(n)。归并排序是一种稳定的排序算法(两个相等的数据,在排序后其先后顺序不变,因为归并不涉及两个相等的数据进行交换)。
&&归并排序的思想
& & &归并排序的思想就是将待排序数列num[n]看做是n个有序数列,然后将相邻的有序表进行归并。归并排序其实就是做两件事:
& & (1)分解:将待排序数列进行折半划分;
& & (2)归并:将划分后的序列段和并排序。
& & &例如:有一待排序序列nums[14, 12, 15, 13, 11, 16],下图是其分解和归并过程:
& & &我们首先来分析第二步归并过程。
& &合并两个有序数列
& & &要想合并两个有序数列很简单,只需要比较两个数列的第一个数,然后取最小的,然后移动被取的那个数列的指针。直到有一个数列取完指针为空,然后再把另一个不为空的数列复制过去。
& & &核心代码为:
//合并有序数组序列,利用辅助数组。
public static void merge(int[] nums, int left, int mid, int right, int[] result) {
int left1 =
int right1 =
int left2 = mid + 1;
int right2 =
int k = 0;
//先把较小的数移入到临时数组
while (left1 &= right1 && left2 &= right2) {
if (nums[left1] &= nums[left2]) {
result[k++] = nums[left1++];
result[k++] = nums[left2++];
//把左边剩余的数移入
while (left1 &= right1) {
result[k++] = nums[left1++];
//把右边剩余的数移入
while (left2 &= right2) {
result[k++] = nums[left2++];
//将排序好的覆盖到nums数组
for (int i = 0; i & i++) {
nums[left + i] = result[i];
}& & &从上边代码中可以看到,我们用了一个临时数组来存储排序好的数据,所以归并排序的空间复杂度为O(n)。合并的时间度是O(n)。
& & 分析完归并后,我们再来看分解。第一步:先把原始数列除以2分为A,B两个部分,然后再将A,B各自一分为二,重复此过程,直到数列只有一个数据了,这意味着这个数列是有序的。可以明显看到,这个过程是一个递归过程,所以用递归方法实现。
& & &归并排序的核心代码
public class MergeSort {
//将待排序数组分解
public static void mergeSort(int[] nums, int left, int right, int[] result) {
if (left & right) {
int mid = (left + right) / 2;
mergeSort(nums, left, mid, result);
mergeSort(nums, mid + 1, right, result);
merge(nums, left, mid, right, result);
//合并有序数组序列,利用辅助数组。
public static void merge(int[] nums, int left, int mid, int right, int[] result) {
int left1 =
int right1 =
int left2 = mid + 1;
int right2 =
int k = 0;
//先把较小的数移入到临时数组
while (left1 &= right1 && left2 &= right2) {
if (nums[left1] &= nums[left2]) {
result[k++] = nums[left1++];
result[k++] = nums[left2++];
//把左边剩余的数移入
while (left1 &= right1) {
result[k++] = nums[left1++];
//把右边剩余的数移入
while (left2 &= right2) {
result[k++] = nums[left2++];
//将排序好的覆盖到nums数组
for (int i = 0; i & i++) {
nums[left + i] = result[i];
& & 归并排序的空间复杂度是O(n),因为其用到了一个大小为n的辅助数组来保存合并排序。
& & &在这里我们分析一下快速排序的空间复杂度:首先快排使用的空间是O(1)的,但其递归调用会消耗空间,因为递归栈(全局)的深度是O(logn)。所以其最优的空间复杂度为O(logn)。最差的情况下空间复杂度为:O(n):退化为冒泡排序的情况。
& & 从空间复杂度来看:堆排序最好O(1),其次是快速排序O(logn),最后是归并排序O(n)。
& & 从稳定性来看:应选归并排序,因为快速排序和堆排序都是不稳定的。
& & &堆排序,快排,归并排序的时间复杂度都是O(nlong)。快排最坏情况下是O(n^2)--退化为冒泡的时候。
& & &综合来看,选快速排序。
我的热门文章

我要回帖

更多关于 归并排序 java视频 的文章

 

随机推荐