n logn java_八大排序算法JAVA实现(时间复杂度O(n*logn)篇)

本文讲述时间复杂度为n*logn的排序算法:归并排序、快速排序、堆排序以及希尔排序的原理、Java实现以及变形应用。

一、归并排序

原理:把两个有序数列合并为一个有序数列。需递归实现。

Java实现:

1 public int[] mergeSort(int[] a, intn)2 {3 return doMergeSort(a, n, 0, n - 1);4 }5 public int[] doMergeSort(int[] a, int n, int start, intend)6 {7 int[] res = new int[n];8 if (n <= 1)9 {10 res[0] =a[start];11 returnres;12 }13 //n>=2时,对其左右数组进行处理

14 int half = n / 2;15 int leftEnd = start + half - 1;16 int rightStart = leftEnd + 1;17 //递归调用本函数,获取有序的左数组以及右数组

18 int[] left =doMergeSort(a, half, start, leftEnd);19 int[] right = doMergeSort(a, n -half, rightStart, end);20 //将左右序列合并

21 int k = 0, i = 0, j = 0;22 while (i < half && j < n -half)23 {//由前往后比较两个序列,取较小值填充到res中,取值后该序列往后移动取下一个值比较

24 if (left[i] <=right[j])25 {26 res[k++] = left[i++];27 }28 else

29 {30 res[k++] = right[j++];31 }32 }33 //剩余的直接放入

34 while (i

二、快速排序

原理:每一次将一个数放在一个左边的数全部比它小,且右边的数全部比它大的位置,然后递归调用函数,将其左右序列排好。这边有一个比较好理解的做法:在数组的左边维护一个小于区间,在遍历的时候,发现比当前数小的数字的时候,将,扩增小于区间,并其放到小于区间内,结束后将当前数填充在小于区间后即可。

Java实现:

1 public int[] quickSort(int[] a, intn)2 {3 doQuickSort(a, n, 0, n - 1);4 returna;5 }6 public void doQuickSort(int[] a, int n, int start, intend)7 {8 if (n > 1)9 {10 int current =a[end];11 int minLen = 0;//小于区间的长度

12 int i =start;13 for (; i < end; i++)14 {15 if (a[i]

17 int temp = a[start +minLen];18 a[start + minLen] =a[i];19 a[i] =temp;20 minLen++;21 }22 }23 a[end] = a[start +minLen];24 a[start + minLen] =current;25 //当前位置已经确定,排左右序列

26 doQuickSort(a, minLen, start, start + minLen - 1);27 doQuickSort(a, n - minLen - 1, start + minLen + 1, end);28 }29 }

变形应用:三色排序练习题

有一个只由0,1,2三种元素构成的整数数组,请使用交换、原地排序而不是使用计数进行排序。给定一个只含0,1,2的整数数组A及它的大小,请返回排序后的数组。保证数组大小小于等于500。

测试样例:

[0,1,1,0,2,2],6

返回:[0,0,1,1,2,2]

解析:运用快排的原理。用数字1来处理,在数组左右各维护一个小于区间和大于区间。

三、堆排序

原理:维护一个大根堆(小根堆同理),即维护一棵二叉树,该数子节点永远比父节点小。每次在大根堆中取出根,根为此时待排序列最大值,放在待排序列最后,然后调整大根堆,重复上诉过程即可。

Java实现:博主不太会插图,关于大小根堆的调整细节可自行百度。原理总结来说是从最后一个非叶子节点开始,往前调整。设当前调整的非叶子节点为n,选举n,n的左,n的右三个节点的最大值作为父节点。且每次调整了靠前的非叶子节点的值后,可能会破坏下面的数的大根堆规则,需要再次调整。嗯我觉得我并没有讲清楚,百度看看图就好。

public int[] heapSort(int[] a, intn)

{for (int len = n; len > 0; len--)

{//len为构建的堆的大小

for (int i = len / 2 - 1; i >= 0; i--)

{//从后往前遍历非叶子节点

while (2 * i + 1

{int j = 2 * i + 1;//左节点序号

if (j + 1 < len && a[j] < a[j + 1])

{

j++;

}if (a[i]

{int temp =a[j];

a[j]=a[i];

a[i]=temp;

i=j;

}else{break;

}

}

}int temp = a[len - 1];

a[len- 1] = a[0];

a[0] =temp;

}returna;

}

变形应用:常规应用如在1000+个数中找出最大的10个数之类的。

已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。 给定一个int数组A,同时给定A的大小n和题意中的k,请返回排序后的数组。

测试样例: [2,1,4,3,6,5,8,7,10,9],10,2

返回:[1,2,3,4,5,6,7,8,9,10]

解析:维护一个大小为k的小根堆,每次调整完这个小根堆后,最小值就会出现在第一位,此时移除第一位,添加后一位数进来,继续调整这个小根堆即可。可以想象为一个从前往后移动的滑动窗口,滑动窗口中是一个小根堆。

四、希尔排序

原理:变形后的插入排序,每个数只与它前面固定步长的倍数的位置进行比对。如:步长step,当前数与它前面step,step*2,step*3....位置进行比较,插入到合适的位置。

Java实现:

public int[] shellSort(int[] a, intn)

{//步长选择

for (int k = 1, step = 10; step > 1; k++)

{

step= n / (2 *k);for (int i = step; i < n; i++)

{if (a[i] < a[i -step])

{int temp =a[i];

a[i]= a[i -step];

a[i- step] =temp;int pre = i -step;while (pre - step > 0)

{if (a[pre] < a[pre -step])

{

temp=a[pre];

a[pre]= a[pre -step];

a[pre- step] =temp;

pre-=step;

}else{break;

}

}

}

}

}returna;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值