排序总结(java版本)

来源:互联网 发布:开源财务系统 php 编辑:程序博客网 时间:2024/06/06 01:19

本文总结的排序算法有简单选择排序、直接插入排序、冒泡排序、希尔排序、快速排序、堆排序、归并排序,桶排序,基数排序。
简单选择排序

private void selectSort(int[] nums){        for(int i = 0; i < nums.length-1; i++){            int index = i;            for(int j = i+1; j < nums.length; j++){                if(nums[j] < nums[index]){                    index = j;                }            }            if(index != i){                int tmp = nums[i];                nums[i] = nums[index];                nums[index] = tmp;            }        }    }

插入排序

private void insertSort(int[] nums){        for(int i = 0; i < nums.length-1; i++){            int index = i+1;            while(index > 0 && nums[index] < nums[index-1] ){                int tmp = nums[index];                nums[index] = nums[index-1];                nums[index-1] = tmp;                index--;            }        }    }

冒泡排序

void bobbleSort(int[] nums){    for(int i = 0; i < nums.length; i++){        for(int j = 0; j < nums.length - i -1; j++){            if(nums[j] > nums[j+1]){                int tmp = nums[j];                nums[j] = nums[j+1];                nums[j+1] = tmp;            }        }    }}

归并排序

    private void mergeSort(int[] nums, int low, int high){        if(low < high){            int mid = (low + high)/2;            mergeSort(nums, low, mid);            mergeSort(nums, mid+1, high);            merge(nums, low, mid, high);        }    }    private void merge(int[] nums, int low, int mid, int high){        int[] tmp = new int[high-low+1];        int i = low, j = mid+1;        int index = 0;        while(i <= mid && j <= high){            if(nums[i] > nums[j]){                tmp[index++] = nums[j++];            }else{                tmp[index++] = nums[i++];            }        }        for(; i <= mid;){            tmp[index++] = nums[i++];        }        for(; j <= high;){            tmp[index++] = nums[j++];        }        for(int k = 0; k < tmp.length; k++){            nums[low+k] = tmp[k];        }    }

快速排序
partition函数
快排里面的partition函数用来解决这样的问题:给定一个数组arr[]和数组中任意一个元素a,重排数组使得a左边都小于它,右边都不小于它。

public class Partition {    public static void main(String[] args) {        // TODO Auto-generated method stub        Partition p = new Partition();        int[] a = {1,4,3,6,7,9,2};        System.out.println(p.partition(a,0,6,2));        for(int i : a){            System.out.print(i + " ");        }    }     // arr[]为数组,start、end分别为数组第一个元素和最后一个元素的索引     // povitIndex为数组中任意选中的数的索引     int partition(int arr[], int start, int end, int pivotIndex)     {         int pivot = arr[pivotIndex];         int tmp = arr[pivotIndex];         arr[pivotIndex] = arr[end];         arr[end] = tmp;         int storeIndex = start;         for(int i = start; i < end; ++i) {             if(arr[i] < pivot) {                 tmp = arr[i];                 arr[i] = arr[storeIndex];                 arr[storeIndex] = tmp;                 ++storeIndex;             }         }         tmp = arr[storeIndex];         arr[storeIndex] = arr[end];         arr[end] = tmp;         return storeIndex;     }}

以上代码作为思想,改进后的快排代码:

void sort(int nums){    quickSort(nums, 0, nums.length - 1);}void quickSort(int[] nums, int low, int high){    if(low >= high){        return;    }    int tmp = nums[low];    int i = low;    int j = high;    while(i < j){        while(i < j && nums[j] >= nums[j-1]){            j--;        }        if(i < j){            nums[i++] = nums[j];        }        while(i < j && nums[i] < nums[i+1]){            i++;        }        if(i < j){            nums[j--] = nums[i];        }    }    nums[i] = tmp;    quickSort(nums, low, i-1);    quickSort(nums, i+1, high);}

希尔排序
比较清晰的思路,作为算法思想的参考,可以直接跳过这个:

private void shellSort1(int[] nums)//Simple implementation    {        int i , j ,gap;        int n = nums.length;        for(gap = n/2; gap > 0; gap /= 2){            for(i = 0; i < gap; i++){                for(j = i + gap; j < n; j += gap){                    if(nums[j] < nums[j-gap]){                        int temp = nums[j];                        int k = j - gap;                        while(k >= 0 && nums[k] > temp){                            nums[k + gap] = nums[k];                            k -= gap;                        }                        nums[k + gap] = temp;                    }                }            }        }    }

比较简洁的代码,还是要用三重循环实现:

private void shellSort2(int[] nums){        int gap, i, j;        for(gap = nums.length/2; gap > 0; gap /= 2){            for(i = gap; i < nums.length; i++){                int temp = nums[i];                for(j = i - gap; j >= 0; j -= gap){                    if(temp < nums[j]){                        nums[j + gap] = nums[j];                    }else{                        break;                    }                }                nums[j + gap] = temp;            }        }    }

堆排序
用数组来存储堆,下标为i的结点,父节点的编号为(i-1)/2,子结点的编号为2*i+1, 2*i+2。
建立堆:每次插入一个元素并调整堆的过程。
插入一个元素:插入到数组最后,更新堆。
删除一个元素:删除发生在nums[0],将最后一个元素调整到nums[0]处,更新堆。
堆排序:堆排序主要包括两步,一是构建堆,二是交换堆顶元素与最后一个元素的位置。

    private void minHeapSort(int[] nums) {        int i;        int len = nums.length;        for(i = len/2-1; i >= 0; i--){            adjustMinHeap(nums, i, len -1);        }        for(i = len-1; i >= 0; i--){            int tmp = nums[0];            nums[0] = nums[i];            nums[i] = tmp;            adjustMinHeap(nums, 0, i - 1);        }    }    private void adjustMinHeap(int[] nums, int pos, int len){        int temp;        int child;        for(temp = nums[pos]; 2 * pos + 1 <= len; pos = child){            child = pos * 2 + 1;            if(child < len && nums[child] > nums[child + 1]){                child++;            }            if(nums[child] < temp){                nums[pos] = nums[child];            }else{                break;            }        }        nums[pos] = temp;    }

基数排序
参考http://blog.csdn.net/lg1259156776/article/details/48783753
以10进制排序为例,
思想:分配和收集。新建10个链表(或数组或其他容器),迭代n次(n为最大数的位数),对迭代i,将数字分配从右到左的第i位数字的桶号,最后按照顺序收集。
用链表来收集(n个),并增加指向链表的尾指针,尾指针2*r(基,此处为10),增加总的空间(n+2*r)。
一般分配代价O(n),收集代价O(r),总代价O(d(r+n))
时间复杂度,平均O(d(r+n)),最坏O(d(n+rd)),最好O(d(r+n))
空间复杂度,O(rd+n)(r代表关键字的基数,d代表长度,n代表关键字的个数)
稳定。
桶排序
建立桶,将一个数据表分到各个桶(每个桶按照分区来接收数据),对非空桶各自排序再按顺序合并。(分治)

算法性能比较

排序算法 最好时间 平均时间 最坏时间 辅助空间 稳定性 备注 简单选择排序 O(n2) O(n2) O(n2) O(1) 不稳定 n小时较好 直接插入排序 O(n) O(n2) O(n2) O(1) 稳定 大部分已有序时较好 冒泡排序 O(n) O(n2) O(n2) O(1) 稳定 n小时较好 希尔排序 O(n) O(nlogn) O(ns) 1<s<2 O(1) 不稳定 s是所选分组 快速排序 O(nlogn) O(nlogn) O(n2) O(logn) 不稳定 n大时较好 堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定 n大时较好 归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定 n大时较好

后来又添加的一些排序算法比较:
排序比较

可参考常用排序算法时间复杂度和空间复杂度。
在这个表格中,n是要被排序的纪录数量以及k是不同键值的数量。
稳定的排序
冒泡排序(bubble sort)— O(n2)
鸡尾酒排序(cocktail sort)—O(n2)
插入排序(insertion sort)—O(n2)
桶排序(bucket sort)—O(n);需要O(k)额外空间
计数排序(counting sort)—O(n+k);需要O(n+k)额外空间
归并排序(merge sort)—O(n log n);需要O(n)额外空间
原地归并排序— O(n2)
二叉排序树排序(binary tree sort)— O(n log n)期望时间; O(n2)最坏时间;需要O(n)额外空间
鸽巢排序(pigeonhole sort)—O(n+k);需要O(k)额外空间
基数排序(radix sort)—O(n·k);需要O(n)额外空间
侏儒排序(gnome sort)— O(n2)
图书馆排序(library sort)— 时间复杂度通常是O(n log n),需要(1+ε)n额外空间

不稳定的排序
选择排序(selection sort)—O(n2)
希尔排序(shell sort)—O(n log2 n)如果使用最佳的现在版本
Clover排序算法(Clover sort)—O(n)期望时间,O(n^2/2)最坏情况
梳排序— O(n log n)
堆排序(heap sort)—O(n log n)
平滑排序(smooth sort)— O(n log n)
快速排序(quick sort)—O(n log n)期望时间, O(n2)最坏情况;对于大的、乱数列表一般相信是最快的已知排序
内省排序(introsort)—O(n log n)
耐心排序(patience sort)—O(n log n + k)最坏情况时间,需要额外的O(n + k)空间,也需要找到最长的递增子序列(longest increasing subsequence)

不实用的排序
Bogo排序— O(n × n!),最坏的情况下期望时间为无穷。
Stupid排序—O(n3);递归版本需要O(n2)额外存储器
珠排序(bead sort)— O(n) or O(√n),但需要特别的硬件
煎饼排序—O(n),但需要特别的硬件
臭皮匠排序(stooge sort)算法简单,但需要约n^2.7的时间

平均时间复杂度由高到低为:
冒泡排序O(n2)
选择排序O(n2)
插入排序O(n2)
希尔排序O(n1.25)
堆排序O(n log n)
归并排序O(n log n)
快速排序O(n log n)
基数排序O(n)
说明:虽然完全逆序的情况下,快速排序会降到选择排序的速度,不过从概率角度来说(参考信息学理论,和概率学),不对算法做编程上优化时,快速排序的平均速度比堆排序要快一些。

0 0
原创粉丝点击