算法Java实现 --- 排序

来源:互联网 发布:方齐禾的淘宝店是什么 编辑:程序博客网 时间:2024/06/07 17:13


一、简单排序

1、冒泡排序

(1)基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。

(2)实例:


(3)Java实现

private static void bubbleSrot(int[] arr) {        for (int i = 0; i < arr.length - 1; i++) {            for (int j = i + 1; j < arr.length; j++) {                if(arr[i] > arr[j]){                    int temp = arr[i];                    arr[i] = arr[j];                    arr[j] = temp;                }            }        }    }

2、选择排序

1)基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;

然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。

2)实例:

3)用java实现

private static void chooseSort(int[] arr) {        for (int i = 0; i < arr.length; i++) {            int least = i;            for (int j = i + 1; j < arr.length; j++) {                if (arr[j] < arr[least]) {                    least = j;                }            }            // 将当前第一个元素与它后面序列中的最小的一个 元素交换,也就是将最小的元素放在最前端            int temp = arr[i];            arr[i] = arr[least];            arr[least] = temp;        }    }  

3、冒泡排序与选择排序的比较

(1)选择排序改进了冒泡排序,将必要的交换次数从O(N²)减少到O(N),不幸的是比较次数依然是O(N²)级。 
然而,选择排序依然为大记录量的排序提出了一个非常重要的改进,因为这些大量的记录需要在内存中移动,这就使交换的时间和比较的时间相比起来,交换的时间更为重要。(一般来说,Java语言中不是这种情况,Java中只是改变了引用位置,而实际对象的位置并没有发生改变)

(2)选择排序的效率:选择排序和冒泡排序执行了相同次数的比较:N*(N-1)/2。对于10个数据项,需要45次比较,然而,10个数据项只需要少于10次的交换。对于100个数据项,需要4950次比较,但只进行不到100次交换。N值很大时,比较的次数是主要的,所以结论是选择排序和冒泡哦排序一样运行了O(N²)时间。但是,选择排序无疑更快,因为它进行的交换少得多。


4、插入排序

(1)基本思想:在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排

好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数

也是排好顺序的。如此反复循环,直到全部排好顺序。

2)实例

(3)用java实现

private static void insertionSort(int[] arr){        int in,out;        for(out = 1 ; out < arr.length ; out ++){            int temp = arr[out];            in = out;            while(in > 0 && arr[in-1] >= temp){                arr[in] = arr[in - 1];                --in;            }            arr[in] = temp;        }    }

算法解释:在外层的for循环中,out变量从1开始,向右移动。它标记了未排序部分的最左端数据。而在内层的while循环中,in变量从out变量开始,向左移动,直到temp变量小于in所指的数组数据项,或者它已经不能再向左移动为止。while循环的每一趟都向左移动了一个已排序的数据项。


插入排序,在一般情况下,比冒泡排序快一倍,比选择排序快一点。


插入排序的效率:这个算法中,第一趟排序,最多比较一次,第二趟排序,最多比较两次,以此类推,最后一趟最多比较N-1次,因此有1+2+3+…+N-1 = N*(N-1)/2。然而,因为在每一趟排序发现插入点之前,平均只有全体数据项的一半真的进行了比较,所以除以2最后是N*(N-1)/4。 
对于随机顺序的数据,插入排序也需要O(N²)的时间级。当数据基本有序,插入排序几乎只需要O(N)的时间,这对把一个基本有序的文件进行排序是一个简单而有效的方法。 
对于逆序排列的数据,每次比较和移动都会执行,所以插入排序不比冒泡排序快。

二、归并排序

(1)基本排序:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

(2)实例:

(3)用java实现

//将两个已排序的数组合并到第三个数组上。    private static void merge(int[] arrA,  int[] arrB,  int[] arrC) {        int aDex = 0, bDex = 0, cDex = 0;        int sizeA = arrA.length;        int sizeB = arrB.length;        // A数组和B数组都不为空        while (aDex < sizeA && bDex < sizeB) {            if (arrA[aDex] < arrB[bDex]) {                arrC[cDex++] = arrA[aDex++];            } else {                arrC[cDex++] = arrB[bDex++];            }        }        //A数组不为空,B数组为空        while (aDex < sizeA) {            arrC[cDex++] = arrA[aDex++];        }        //A数组为空,B数组不为空        while (bDex < sizeB) {            arrC[cDex++] = arrB[bDex++];        }    }

于是,详细的完整实现如下:

static class DArray{        private int [] theArray;        public DArray(int[] theArray) {            this.theArray = theArray;        }        //执行归并排序        public void mergeSort(){            //复制一份出来            int [] workSpace = new int [theArray.length];            reMergeSort(workSpace, 0, theArray.length-1);        }        private void reMergeSort(int [] workSpace,int lowerBound,int upperBound) {            if(lowerBound == upperBound){                return;            }else{                int mid = (lowerBound + upperBound) / 2;                reMergeSort(workSpace, lowerBound, mid);                reMergeSort(workSpace, mid + 1, upperBound);                merge(workSpace, lowerBound, mid + 1,upperBound);            }        }        private void merge(int [] workSpace,int lowPtr,int highPtr,int upperBound){            int j= 0;//workSpace's index            int lowerBound = lowPtr;            int mid = highPtr -1;            int n = upperBound - lowerBound + 1;            while(lowPtr <= mid && highPtr <= upperBound){                if(theArray[lowPtr] < theArray[highPtr]){                    workSpace[j++] = theArray[lowPtr++];                }else{                    workSpace[j++] = theArray[highPtr++];                }            }            while(lowPtr <= mid){                workSpace[j++] = theArray[lowPtr++];            }            while(highPtr <= upperBound){                workSpace[j++] = theArray[highPtr++];            }            for(j = 0;j < n ;j++){                theArray[lowerBound+j] = workSpace[j];            }        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

运行测试:

int b[] = new int[] { 3, 4, 1, 5, 5, 6, 8, 9, 7 };DArray dArray = new DArray(b);dArray.mergeSort();System.out.println(Arrays.toString(b));//输出结果:[1, 3, 4, 5, 5, 6, 7, 8, 9]
三、高级排序


有2个高级的排序算法,希尔排序和快速排序。这两种排序算法都比简单排序算法快得多:希尔排序大约需要O(N*(logN)²)时间,快速排序需要O(N*logN)时间。这两种排序算法都和归并排序不同,不需要大量的辅助存储空间。希尔排序几乎和归并排序一样容易实现,而快速排序是所有通用排序算法中最快的一种排序算法。 
还有一种基数排序,是一种不常用但很有趣的排序算法。

1、希尔排序(最小增量排序)-- 基于 插入排序

1)基本思想:算法先将要排序的一组数按某个增量dn/2,n为要排序数的个数)分成若干组,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成。

2)实例:

(3)用java实现

private static void shellSort(int[] arr) {        int inner, outer;        int temp;        int h = 1;        int nElem = arr.length;        while (h <= nElem / 3) {            h = h * 3 + 1;        }        while (h > 0) {            for (outer = h; outer < nElem; outer++) {                temp = arr[outer];                inner = outer;                while (inner > h - 1 && arr[inner - h] >= temp) {                    arr[inner] = arr[inner - h];                    inner -= h;                }                arr[inner] = temp;            }            h = (h - 1) / 3;        }    }


2、快速排序

1)基本思想:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

2)实例:

3)用java实现

//快速排序    private static void recQuickSort(int arr [] ,int left,int right){        if(right - left <= 0){            return;        }else{            int pivot = arr[right];//一般使用数组最右边的元素作为枢纽            int partition = partitionIt(arr, left, right, pivot);            recQuickSort(arr, left, partition-1);            recQuickSort(arr, partition+1, right);        }    }    //划分    private static int partitionIt(int[] arr ,int left,int right,int pivot){        int leftPtr = left - 1;        //int rightPtr = right + 1;        int rightPtr = right ; //使用最右边的元素作为枢纽,划分时就要将最右端的数据项排除在外        while(true){            while(arr[++leftPtr] < pivot);            while(rightPtr > 0 && arr[--rightPtr] > pivot);            if(leftPtr >= rightPtr){                break;            }else{                //交换leftPtr和rightPtr位置的元素                int temp = arr[leftPtr];                arr[leftPtr] = arr[rightPtr];                arr[rightPtr] = temp;            }        }        //交换leftPtr和right位置的元素        int temp = arr[leftPtr];        arr[leftPtr] = arr[right];        arr[right] = temp;        return leftPtr;//返回枢纽位置    }
最后测试,10万条随机数据,排序完成耗时18~25ms。希尔排序耗时差不多,而简单排序中的插入排序和选择排序耗时3500ms以上,冒泡排序最慢,超过17000ms以上才完成;归并排序比希尔排序和快速排序稍微慢点,在30ms左右。


原创粉丝点击