算法之八大排序算法

这里写图片描述

1、直接插入排序

插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
这里写图片描述

public static void InsertSort(int[] array){
        if(array == null || array.length == 0)
            return ;
        for(int i = 0;i < array.length; i++){
            int value = array[i];
            int j;
            for( j = i - 1; j >= 0; j--){
                if(value < array[j]){
                    array[j + 1] = array[j];
                }else{
                    break;
                }
            }
            array[j + 1] = value;
        }
    }

2、 希尔排序

希尔排序示意图

这里写图片描述
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率
但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位
希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列,对所有的子序列同时分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。

算法步骤:

1)选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;

2)按增量序列个数k,对序列进行k 趟排序;

3)每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

 public static void ShellSort(int[] array){
        if(array == null || array.length == 0)
            return ;
        for(int gap = (array.length/2); gap > 0; gap/=2){
            for(int i = gap; i < array.length; i++)
                for(int j = i-gap; j>=0 && array[j]>array[j+gap]; j -= gap) {
                    int temp = array[j];
                    array[j] = array[j+gap];
                    array[j+gap] = temp;
                }
        }
    }

3、直接选择排序

步骤:每次从未排序序列中选择最小(最大)元素放在已排序序列的尾部
这里写图片描述

public static void SelectSort(int[] array){
        if(array == null || array.length == 0)
            return ;
        for(int i = 0;i < array.length; i++){
            int minindex = array[i];
            for(int j = i; j < array.length; j++){
                if(array[j] < minindex)
                    minindex = j;
            }
            if(minindex != i){
                int temp = array[i];
                array[i] = array[minindex];
                array[minindex] = temp;
            }
        }
    }

4、堆排序

这里写图片描述

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
这里写图片描述

同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子
这里写图片描述

该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:

大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

算法步骤:

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

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

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

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

   //本函数功能是:根据数组array构建大根堆
    //从第i个元素开始向下调整
    public static void adjustHeap(int []arr,int i,int length){
        for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
            if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
                k++;
            }
            if(arr[k] >arr[i]){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
                int temp = arr[i];
                arr[i] = arr[k];
                i = k;
                arr[k] = temp;
            }else{
                break;
            }
        }
    }
    //堆排序算法
    public static void  HeapSort(int array[]){
        //1.构建大顶堆,目的只是保证堆顶元素值最大
        //保证堆从上到下大致有序看,任意从节点到叶子节点的路径上元素是有序的
        for(int i=array.length/2-1;i>=0;i--){
            //从第一个非叶子结点(即array.length/2 - 1)从下至上,从右至左调整结构
            adjustHeap(array,i,array.length);
        }
        //2.调整堆结构+交换堆顶元素与末尾元素,
        for(int j=array.length-1;j>0;j--){
            array[j] = array[0] ^ array[j];//将堆顶元素与末尾元素进行交换
            array[0] = array[0] ^ array[j];
            array[j] = array[0] ^ array[j];
            adjustHeap(array,0,j);//重新对堆进行调整
        }
    }

5、冒泡排序

这里写图片描述
冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

public static void BubbleSort(int[] array){
        if(array == null || array.length == 0)
            return ;
        for(int i = array.length - 1;i > 0; i--){
            for(int j = 0 ;j < i;j++ ){
                if(array[j] > array[j+1]){
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                 }
            }
        }
    }

6、 快速排序

这里写图片描述
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。

快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

public static void Qsort(int[] array,int start,int end) {
        if(array == null || array.length == 0)
            return ;
        if(start > end)
            return ;
        else{
            int i = start;
            int j = end;
            int flag = array[end];
            while(i < j){
                while(array[i] <= flag && i<j){
                    i++;
                }
                if(array[i] > flag && j > i){
                    array[j] = array[i];
                    array[i] = flag;
                    j--;
                }
                while(array[j] >= flag && j>i){
                    j--;
                }
                if(array[j] < flag && i<j){
                    array[i] = array[j];
                    array[j] = flag;
                    i++;
                }
            }
            array[i] = flag;
            Qsort(array,start,i - 1);
            Qsort(array,i + 1,end);
        }
    }

7、归并排序

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

算法步骤:

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

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

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

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

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

public static void MergeSort(int[] copy,int[] array,int start,int end){
        if(array == null || array.length == 0)
            return ;
        if(start >= end)
            return ;
        int middle = (end - start )/2;
        MergeSort(copy,array,start,start + middle);
        MergeSort(copy,array,start + middle + 1,end);

        int i = start + middle;
        int j = end;
        int index = end;
        while(i >= start && i <= (start + middle) && j >= (start + middle + 1) && j <= end){
            if(copy[i] > copy[j]){
                array[index--] = copy[i--];
            }else{
                array[index--] = copy[j--];
            }
        }
        while(i >= start && i <= (start + middle) && index >= start){
            array[index--] = copy[i--];
        }
        while(j >= (start + middle + 1) && j <= end && index >= start){
            array[index--] = copy[j--];
        }
        for(int m = start;m <= end;m++){
            copy[m] = array[m];
        }
    }

8、基数排序 (即桶排序)

典型的以空间换时间,时间复杂度为线性时间

猜你喜欢

转载自blog.csdn.net/sixingmiyi39473/article/details/79383338