总结一下面试当中经常问到的排序算法:
1、冒泡排序:
package com.zj.sort;
public class MaoPaoSort {
public void Sort(int[] array){ //冒泡程序主要是冒泡的过程,两两交换
for(int i= 0 ;i<array.length;i++){
for(int j= array.length-1;j>=i+1;j--){
if(array[j] < array[j-1]){
int tmp = array[j];
array[j] = array[j-1];
array[j-1] = tmp;
}
}
}
}
public static void main(String[] arqs){
int[] test = new int[]{3,4,1,2,1,3,6,5,4};
MaoPaoSort ms = new MaoPaoSort();
ms.Sort(test);
for(int i=0;i<test.length;i++){
System.out.println(String.format("第%d个数字:%d", i,test[i]));
}
}
}
冒泡排序最坏的情况是54321要排成12345。考虑这种情况的算法复杂度O() = n*(n-1)+(n-1)*(n-2)+.....+2*1=O(n^2)
最好的情况呢?尼玛,好像我的写法没有最好的情况。。。原来数组12345排成12345,复杂度也是O(n^2)
2、快速排序:
package com.zj.sort;
public class QuickSort { //递归调用,每递归一次将数组分成三段:left_sub_array,array[i],right_sub_array
//选择标称值很关键,影响效率;下面的算法partition函数效率上做了优化
public void MyQuickSort(int[] array){
quicksort(array, 0, array.length-1);
}
public void quicksort(int[] array,int left,int right){
if(left < right){
int q = partition(array,left,right);
quicksort(array, left, q-1);
quicksort(array, q+1, right);
}
}
public int partition(int[] array,int left,int right){
int x = array[right];
int i = left -1;
for(int j = left;j<=right;j++){
if(array[j] < x && i < j){
i++;
if(i != j){
int k = array[j];
array[j] = array[i];
array[i] = k;
}
}
}
int k = array[right];
array[right] = array[i+1];
array[i+1] = k;
return i+1;
}
public static void main(String[] arqs){
int[] test = new int[]{2,4,1,5,6,8,2,0};
QuickSort qs = new QuickSort();
qs.MyQuickSort(test);
for(int i=0;i<test.length;i++){
System.out.println(String.format("第%d个数字:%d", i,test[i]));
}
}
}
快速排序影响效率的是数组分left_sub_array,array[i+1],right_sub_array的过程。i表示由于array[i+1]的子数组的最后一个索引。代码中将array[i+1]的值设为array[right],不过赋值的过程在最后,因为i的索引位置到最后才确定;i的初始值为left-1,假设left_sub_array为空;后面慢慢将right_sub_array中小于x的值移到left_sub_array中(移动的过程中同时i++,即增到left_sub_array的长度)
代码中我们初始假设left_sub_array为空,所以对应的算法的最坏情况就是,数组都小于等于x的情况(把right_sub_array中的数据搬移到left_sub_array中);这种情况会进入if,执行i++操作,但不会执行交换操作,复杂度O(n);再考虑递归:O(n)=O(n-1)+c.N;O(n)=O(1)+c(2+3+4....+N)=O(n^2);
快速排序的平均算法复杂度比较难推到,记得是O(n.logn)
3、堆排序
package com.zj.sort;
public class HeapSort { //堆排序,通过递归调用将最大的元素放到堆顶;有构造最大堆的过程,还有最大堆更新的过程
private int dataLen;
public void Sort(int[] array) {
dataLen = array.length;
buildMaxHeap(array);
for(int i=dataLen -1;i>=1;i--){
int k = array[i];
array[i] = array[0];
array[0] = k;
dataLen--;
max_heapify(array, 0);
}
}
public void max_heapify(int[] data, int i) {
int child_l = 2 * i + 1;
int child_r = 2 * (i + 1);
int largest =i;
if(child_l < dataLen && data[child_l] > data[largest])
largest = child_l;
if(child_r <dataLen && data[child_r]> data[largest])
largest = child_r;
if(largest != i){
int k = data[i];
data[i] = data[largest];
data[largest] = k;
max_heapify(data, largest);
}
}
public void buildMaxHeap(int[] data) {
for(int i = (dataLen-1)/2;i >=0;i--){
max_heapify(data, i);
}
}
public static void main(String[] arqs){
int[] test = new int[]{3,1,4,6,2,3,7,1,9};
HeapSort hs = new HeapSort();
hs.Sort(test);
for(int i=0;i<test.length;i++){
System.out.println(String.format("第%d个数字:%d", i,test[i]));
}
}
}
4、计数排序
package com.zj.sort;
public class CountSort { //计数排序需要知道数组的值范围,然后用散列表的形式记录值的位置
//效率高的情况:值分布密集,(下列算法可以优化:如果值密集的分布在900~1000,散列算法可以优化,节约内存)
public int[] Sort(int[] data,int max_limit){
int[] tmp = new int[max_limit];
int[] des = new int[data.length];
for(int i=0;i<data.length;i++){
tmp[data[i]] +=1;
}
for(int j = 1;j<max_limit;j++){
tmp[j] +=tmp[j-1]; //数字x在数组中的位置
}
for(int i=0;i<data.length;i++){
des[tmp[data[i]]-1] = data[i];
tmp[data[i]] --;
}
return des;
}
public static void main(String[] arqs){
int[] test = new int[]{4,1,5,2,7,3,8};
CountSort cs = new CountSort();
test = cs.Sort(test, 20);
for(int i =0;i<test.length;i++){
System.out.println(String.format("第%d个位置:%d", i,test[i]));
}
}
}
5、桶排序
package com.zj.sort;
public class BucketSort { //均匀分布 0~20之间 适用于均匀分布,hash表的类似 实现,效率高的情况是链表长度均匀
public static void main(String[] arqs){
int[] test = new int[]{2,2,1,4,3,6,5,7,8,6,9,13,12,15,17,18};
BucketSort bs = new BucketSort();
test =bs.Sort(test);
for(int i=0;i<test.length;i++){
System.out.println(String.format("第%d个数字:%d", i,test[i]));
}
}
public int[] Sort(int[] array){
int[] des = new int[array.length];
Bucket[] tmp = new Bucket[5];
for(int i =0;i<tmp.length;i++)
tmp[i] = new Bucket(0, null);
for(int i=0;i<array.length;i++){
Bucket bucket = new Bucket(array[i], null);
bucket_into_sort(tmp[(array[i]/4)], bucket);
}
int j=0;
for(int i=0;i<tmp.length;i++){
Bucket k = tmp[i];
k = k.next;
while(k !=null){
des[j++] = k.value;
k = k.next;
}
}
return des;
}
public void bucket_into_sort(Bucket src_bucket,Bucket bucket){
Bucket tmp = src_bucket.next;
if(tmp == null){
src_bucket.next = bucket;
return;
}
while(tmp != null){
if(tmp.value > bucket.value){
bucket.next = tmp;
src_bucket.next = bucket;
return;
}
src_bucket = src_bucket.next;
tmp = tmp.next;
}
src_bucket.next = bucket;
}
}
class Bucket{
public int value;
public Bucket next;
public Bucket(int value,Bucket bucket){
this.value = value;
this.next = bucket;
}
}