您的位置:首页 > 其它

排序算法总结

2018-01-19 00:03 302 查看
      




如上图所说,排序内常见7种排序: 冒泡、简单选择、直接插入、 希尔排序、堆排序、归并排序、快速排序。

按照待排序的记录是否全部放在内存,排序可分为两种排序:内排序和外排序。

冒泡排序:耳熟能详,相邻的两两比较并交换,直到最后一位。

 

 




冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就

把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小

的元素会经由交换慢慢“浮”到数列的顶端。也就是双重循环就可以搞定的问题但是需要注意下一边界



上述代码加了一个 judge用于优化冒泡,防止没有数据交换时,不用再循环判断。
简单选择排序:通过对(n-i)次数组的比较,在和 n - i +1记录中选出关键字最小的记录,和第i记录交换。





选择排序(Selection sort)也是一种简单直观的排序算法。

算法步骤:

1)首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置

2)再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

3)重复第二步,直到所有元素均排序完毕。

[java] view
plain copy

<span style="font-family:Microsoft YaHei;font-size:14px;">  public int[] ChoseSort(int[] intArr){    

        for(int i=0;i<intArr.length;i++){    

            int lowIndex = i;    

                

            for(int j=i+1;j<intArr.length;j++){    

                if(intArr[j]<intArr[lowIndex]){    

                    lowIndex = j;    

                }    

            }    

                

            //将当前第一个元素与它后面序列中的最小的一个 元素交换,也就是将最小的元素放在最前端    

            int temp = intArr[i];               

            intArr[i] = intArr[lowIndex];    

            intArr[lowIndex] = temp;    

        }    

            

        return intArr;    

    } </span>  



直接插入排序:将一个激励插入到已经排列好的有序表中,得到新的记录表。



 平均移动次数为 n^2/4,比冒泡和简单选择排序好一些。

希尔排序:使用跳跃分割,首先对数组进行部分的比较排序,然后再跳跃分割。
 


这里,可以使用个比喻:捕鱼时,我们使用大孔(大的跳跃间隔)的网捕鱼。但是河里的鱼必须要补完,就用小孔的 

(小的跳跃间隔)网捕鱼,最终把鱼补完。



堆排序: 这里有点尴尬了。我的理解就是二叉树排序。详情请点击链接



堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:

即子结点的键值或索引总是小于(或者大于)它的父节点。

堆排序的平均时间复杂度为Ο(nlogn) 。

算法步骤:

1)创建一个堆H[0..n-1]

2)把堆首(最大值)和堆尾互换

3)把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置

4) 重复步骤2,直到堆的尺寸为1

归并排序:详情请点击链接



归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一

个非常典型的应用。

算法步骤:

1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置

3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

4. 重复步骤3直到某一指针达到序列尾

5. 将另一序列剩下的所有元素直接复制到合并序列尾

[java] view
plain copy

<span style="font-family:Microsoft YaHei;font-size:14px;">  public static int[] sort(int[] nums, int low, int high) {    

        int mid = (low + high) / 2;    

        if (low < high) {    

            // 左边    

            sort(nums, low, mid);    

            // 右边    

            sort(nums, mid + 1, high);    

            // 左右归并    

            merge(nums, low, mid, high);    

        }    

        return nums;    

    }    

    

    public static void merge(int[] nums, int low, int mid, int high) {    

        int[] temp = new int[high - low + 1];    

        int i = low;// 左指针    

        int j = mid + 1;// 右指针    

        int k = 0;    

    

        // 把较小的数先移到新数组中    

        while (i <= mid && j <= high) {    

            if (nums[i] < nums[j]) {    

                temp[k++] = nums[i++];    

            } else {    

                temp[k++] = nums[j++];    

            }    

        }    

    

        // 把左边剩余的数移入数组    

        while (i <= mid) {    

            temp[k++] = nums[i++];    

        }    

    

        // 把右边边剩余的数移入数组    

        while (j <= high) {    

            temp[k++] = nums[j++];    

        }    

    

        // 把新数组中的数覆盖nums数组    

        for (int k2 = 0; k2 < temp.length; k2++) {    

            nums[k2 + low] = temp[k2];    

        }    

    }  </span>  

快速排序:详情请点击链接



快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,

但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
 快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

算法步骤:

1) 从数列中挑出一个元素,称为 “基准”(pivot),

2 )重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。

3 )递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

[java] view
plain copy

<span style="font-family:Microsoft YaHei;font-size:14px;">    private static void quick_sort(int[] arr, int low, int high) {  

        // 解决和合并  

        if (low <= high) {  

            int mid = partition(arr, low, high);  

            // 递归  

            quick_sort(arr, low, mid - 1);  

            quick_sort(arr, mid + 1, high);  

        }  

  

    }  

  

    private static int partition(int[] arr, int low, int high) {  

        // 分解  

        int pivot = arr[high];  

        int i = low - 1;  

        int temp;  

        for (int j = low; j < high; j++) {  

  

            if (arr[j] < pivot) {  

                i++;  

                temp = arr[i];  

                arr[i] = arr[j];  

                arr[j] = temp;  

            }  

        }  

        // 交换中间元素和privot  

        temp = arr[i + 1];  

        arr[i + 1] = arr[high];  

        arr[high] = temp;  

        return i + 1;  

  

    }</span>  

 关于算法的总结请点击链接数据结构



归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

算法步骤:

1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置

3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

4. 重复步骤3直到某一指针达到序列尾

5. 将另一序列剩下的所有元素直接复制到合并序列尾

[java] view
plain copy

<span style="font-family:Microsoft YaHei;font-size:14px;">  public static int[] sort(int[] nums, int low, int high) {    

        int mid = (low + high) / 2;    

        if (low < high) {    

            // 左边    

            sort(nums, low, mid);    

            // 右边    

            sort(nums, mid + 1, high);    

            // 左右归并    

            merge(nums, low, mid, high);    

        }    

        return nums;    

    }    

    

    public static void merge(int[] nums, int low, int mid, int high) {    

        int[] temp = new int[high - low + 1];    

        int i = low;// 左指针    

        int j = mid + 1;// 右指针    

        int k = 0;    

    

        // 把较小的数先移到新数组中    

        while (i <= mid && j <= high) {    

            if (nums[i] < nums[j]) {    

                temp[k++] = nums[i++];    

            } else {    

                temp[k++] = nums[j++];    

            }    

        }    

    

        // 把左边剩余的数移入数组    

        while (i <= mid) {    

            temp[k++] = nums[i++];    

        }    

    

        // 把右边边剩余的数移入数组    

        while (j <= high) {    

            temp[k++] = nums[j++];    

        }    

    

        // 把新数组中的数覆盖nums数组    

        for (int k2 = 0; k2 < temp.length; k2++) {    

            nums[k2 + low] = temp[k2];    

        }    

    }  </span>  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: