排序算法总结篇(一)

前言

在学习过程中,算法是我们绕不过去的槛,可能我们没有特体经过系统的学习,但是,实际上平时的代码中已经体现了很多的算法思想,以中兴算法大赛2017年中兴算法大赛 迪杰特斯拉派为列,里面自己其实用到了很多算法,只是自己并没有将它与理论结合起来看。


1.概述

首先,我们来看一张经典的图,这张图很详细讲常见的算法做了归类:

这里写图片描述

排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。

我们这里说说八大排序就是内部排序。

先看一下他们的复杂度,然后再分别对他们介绍,比较,总结他们的优点,分析适用的场景。

这里写图片描述

-1.选择排序:不稳定,时间复杂度 O(n^2)

选择排序的基本思想是对待排序的记录序列进行n-1遍的处理,第i遍处理是将L[i..n]中最小者与L[i]交换位置。这样,经过i遍处理之后,前i个记录的位置已经是正确的了。

- 2.插入排序:稳定,时间复杂度 O(n^2)

插入排序的基本思想是,经过i-1遍处理后,L[1..i-1]己排好序。第i遍处理仅将L[i]插入L[1..i-1]的适当位置,使得L[1..i] 又是排好序的序列。要达到这个目的,我们可以用顺序比较的方法。首先比较L[i]和L[i-1],如果L[i-1]≤ L[i],则L[1..i]已排好序,第i遍处理就结束了;否则交换L[i]与L[i-1]的位置,继续比较L[i-1]和L[i-2],直到找到某一个位置j(1≤j≤i-1),使得L[j] ≤L[j+1]时为止。图1演示了对4个元素进行插入排序的过程,共需要(a),(b),(c)三次插入。

- 3.冒泡排序:稳定,时间复杂度 O(n^2)

冒泡排序方法是最简单的排序方法。这种方法的基本思想是,将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮。在冒泡排序算法中我们要对这个“气泡”序列处理若干遍。所谓一遍处理,就是自底向上检查一遍这个序列,并时刻注意两个相邻的元素的顺序是否正确。如果发现两个相邻元素的顺序不对,即“轻”的元素在下面,就交换它们的位置。显然,处理一遍之后,“最轻”的元素就浮到了最高位置;处理二遍之后,“次轻”的元素就浮到了次高位置。在作第二遍处理时,由于最高位置上的元素已是“最轻”元素,所以不必检查。一般地,第i遍处理时,不必检查第i高位置以上的元素,因为经过前面i-1遍的处理,它们已正确地排好序。

- 4.堆排序:不稳定,时间复杂度 O(nlog n)

堆排序是一种树形选择排序,在排序过程中,将A[n]看成是完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最小的元素。

- 5.归并排序:稳定,时间复杂度 O(nlog n)

设有两个有序(升序)序列存储在同一数组中相邻的位置上,不妨设为A[l..m],A[m+1..h],将它们归并为一个有序数列,并存储在A[l..h]。

- 6.快速排序:不稳定,时间复杂度 最理想 O(nlogn) 最差时间O(n^2)

快速排序是对冒泡排序的一种本质改进。它的基本思想是通过一趟扫描后,使得排序序列的长度能大幅度地减少。在冒泡排序中,一次扫描只能确保最大数值的数移到正确位置,而待排序序列的长度可能只减少1。快速排序通过一趟扫描,就能确保某个数(以它为基准点吧)的左边各数都比它小,右边各数都比它大。然后又用同样的方法处理它左右两边的数,直到基准点的左右只有一个元素为止。

-7.希尔排序:不稳定,时间复杂度 平均时间 O(nlogn) 最差时间O(n^s)
在直接插入排序算法中,每次插入一个数,使有序序列只增加1个节点,并且对插入下一个数没有提供任何帮助。如果比较相隔较远距离(称为 增量)的数,使得数移动时能跨过多个元素,则进行一次比较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。


2.算法介绍

2.1 插入排序—直接插入排序(Straight Insertion Sort)

基本思想:

将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
要点:设立哨兵,作为临时存储和判断数组边界之用。

如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。

算法的实现:

public static void selectSort(int[] array) {  
    int position = 0;  
    for (int i = 0; i < array.length; i++) {  
        int j = i + 1;  
        position = i;  
        int temp = array[i];  
        for (; j < array.length; j++) {  
            if (array[j] < temp) {  
                temp = array[j];  
                position = j;  
            }  
        }  
        array[position] = array[i];  
        array[i] = temp;  
    }  
    System.out.println(Arrays.toString(array) + " selectSort");  
} 

2.2 希尔排序

基本思想:

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
先取一个正整数d1 < n, 把所有相隔d1的记录放一组,每个组内进行直接插入排序;然后d2 < d1,重复上述分组和排序操作;直至di = 1,即所有记录放进一个组中排序为止。

这里写图片描述

算法实现:


 public static void shellSort(int[] array) {   //希尔排序
        int i;  
        int j;  
        int temp;  
        int gap = 1;  
        int len = array.length;  
        while (gap < len / 3) { gap = gap * 3 + 1; }  
        for (; gap > 0; gap /= 3) {  
            for (i = gap; i < len; i++) {  
                temp = array[i];  
                for (j = i - gap; j >= 0 && array[j] > temp; j -= gap) {  
                    array[j + gap] = array[j];  
                }  
                array[j + gap] = temp;  
            }  
        }  
        System.out.println(Arrays.toString(array) + " shellSort");  
    } 

2.3 简单排序

基本思想:

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

这里写图片描述

算法实现:

    public static void selectSort(int[] number){//简单排序
        int size = number.length,temp;
        for(int i=0;i<size-1;i++){
            int k=i;
            for(int j=i+1;j<size;j++){
                if(number[j]<number[k]){
                    k = j;
                }
            }
            temp = number[k];
            number[k]=number[i];
            number[i]=temp;
        }
    }

2.4 堆排序

基本思想:

堆的定义如下:具有n个元素的序列(h1,h2,…,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1)(i=1,2,…,n/2)时称之为堆。在这里只讨论满足前者条件的堆。由堆的定义可以看出,堆顶元素(即第一个元素)必为最大项(大顶堆)。完全二叉树可以很直观地表示堆的结构。堆顶为根,其它为左子树、右子树。初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。

算法实现:

public static void heapSort(int[] array) {  
    /* 
     *  第一步:将数组堆化 
     *  beginIndex = 第一个非叶子节点。 
     *  从第一个非叶子节点开始即可。无需从最后一个叶子节点开始。 
     *  叶子节点可以看作已符合堆要求的节点,根节点就是它自己且自己以下值为最大。 
     */  
    int len = array.length - 1;  
    int beginIndex = (len - 1) >> 1;  
    for (int i = beginIndex; i >= 0; i--) {  
        maxHeapify(i, len, array);  
    }  
    /* 
     * 第二步:对堆化数据排序 
     * 每次都是移出最顶层的根节点A[0],与最尾部节点位置调换,同时遍历长度 - 1。 
     * 然后从新整理被换到根节点的末尾元素,使其符合堆的特性。 
     * 直至未排序的堆长度为 0。 
     */  
    for (int i = len; i > 0; i--) {  
        swap(0, i, array);  
        maxHeapify(0, i - 1, array);  
    }  
    System.out.println(Arrays.toString(array) + " heapSort");  
}  
private static void swap(int i, int j, int[] arr) {  
    int temp = arr[i];  
    arr[i] = arr[j];  
    arr[j] = temp;  
}  
/** 
 * 调整索引为 index 处的数据,使其符合堆的特性。 
 * 
 * @param index 需要堆化处理的数据的索引 
 * @param len   未排序的堆(数组)的长度 
 */  
private static void maxHeapify(int index, int len, int[] arr) {  
    int li = (index << 1) + 1; // 左子节点索引  
    int ri = li + 1;           // 右子节点索引  
    int cMax = li;             // 子节点值最大索引,默认左子节点。  
    if (li > len) {  
        return;       // 左子节点索引超出计算范围,直接返回。  
    }  
    if (ri <= len && arr[ri] > arr[li]) // 先判断左右子节点,哪个较大。  
    { cMax = ri; }  
    if (arr[cMax] > arr[index]) {  
        swap(cMax, index, arr);      // 如果父节点被子节点调换,  
        maxHeapify(cMax, len, arr);  // 则需要继续判断换下后的父节点是否符合堆的特性。  
    }  
}  
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值