数据结构:排序算法

排序算法

<<插入排序>>

*直接插入排序*

思想

每次取剩下的一个元素插入到已经有序的序列中.

代码

public static void InsertSort(int[] arr){
        if(arr == null || arr.length == 0){
            System.err.println("ERROR INPUT");
            return;
        }

        int n = arr.length;

        for(int i = 1; i < n; i++){

            int temp = arr[i];
            int j = i - 1;
            while(j >= 0 && temp < arr[j]){
                arr[j+1] = arr[j];
                j--;
            }

            arr[j+1] = temp;
        }
    }

算法分析

*最好情况下:每次循环,内层都不需要比较,只有外层循环的常量级操作,时间复杂度为O(n)

*最坏情况下:内层循环每次都要比较i次,故总的执行次数是:1+2+3+…+n=n*(n-1)/2,故时间复杂度为O(n2)

*最后平均时间复杂度为:O(n2)

*空间复杂度:O(1)

*折半插入排序*

思想

基本思想与直接插入是一样的,区别在于寻找插入位置的方法不同,折半插入排序是采用折半查找来寻找插入位置的.

代码

public static void halfInsertSort(int[] arr){
        if(arr == null || arr.length == 0){
            System.err.println("ERROR INPUT");
            return;
        }

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

            int temp = arr[i];

            int low = 0;
            int high = i - 1;
            int idx = -1;
            while(low <= high){
                int m = (low+high)/2;

                if(arr[m] < temp){
                    low = m+1;
                }else if(arr[m] > temp){
                    high = m-1;
                }else{
                    idx = m+1;
                    break;
                }
            }
            if(low > high){
                idx = high + 1;
            }

            for(int j = i-1; j >= idx; j--){
                arr[j+1] = arr[j];
            }

            arr[idx] = temp;
        }

    }

算法分析

*外层循环为n-1次,内层循环是折半查找,

*最好情况是:复杂度为O(logn).故总的时间复杂度为O(nlogn);最坏情况是O(n2);平均情况为O(n2).

*空间复杂度为:O(1)

*希尔排序(shellsort)*

希尔排序,又称缩小增量排序,其本质还是插入排序,只不过将待排序的序列按某种规则分为几个子序列,分别对这几个子序列进行直接插入排序.这个规则就是增量

思想

比如对序列:49, 38, 65, 97, 76, 13, 27, 49

先选择3为增量,则得到序列1:49, 97, 27;序列2:38,76, 49;序列3:65, 13

分别对这三个使用直接插入排序,序列1:27,49,97;序列2:38,49,76;序列3:13,65

将三个序列合并起来:27,38,13,49,49,65,97,76

这就是一趟希尔排序了.接下来,再也2(或1)为增量进行一趟希而排序

代码

算法分析

平均时间复杂度:O(nlogn)

空间复杂度:O(1)

<<交换排序>>

*冒泡排序*

思想

每次通过一系列的交换动作,将最大(或最小)的数字冒出来.终止条件是一趟排序过程中没有发生元素交换

代码

public static void BubbleSort(int[] arr){
        if(arr == null || arr.length == 0){
            System.err.println("Error input");
            return;
        }

        for(int i = arr.length-1; i >= 1; i--){

            boolean flag = false;
            for(int j = 0; j < i; j++){
                if(arr[j] > arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;

                    flag = true;
                }
            }

            if(flag == false){
                return;
            }
        }
    }

算法分析

时间复杂度:最好O(n)最坏O(n2)平均O(n2)

空间复杂度:O(1)

*快速排序*

思想

>快速排序也是"交换"类的排序,它的基本思想是找出一个枢纽,使得在它左边的比它小,右边的比它大.

代码

public static void QuickSort(int[] arr, int l, int r){
        if(arr == null || arr.length == 0 || l < 0 || r >= arr.length){
            System.err.println("ERROR INPUT");
            return;
        }

        int i = l;
        int j = r;
        if(l < r){
            int temp = arr[l];
            while(i != j){
                while(j > i && arr[j] > arr[i]){
                    j--;
                }

                if(i < j){
                    arr[i] = arr[j];
                    i++;
                }

                while(j > i && arr[i] < arr[j]){
                    i++;
                }
                if(i < j){

                    arr[j] = arr[i];
                    j--;
                }

            }

            arr[i] = temp;
            QuickSort(arr, l, i-1);
            QuickSort(arr, i+1, r);
        }
    }

另外一个写法:

    public int Partition(char[] arr, int start, int end){
        if(arr == null || arr.length == 0 || start < 0 || end < 0){
            return -1;
        }

        int index = start + (int)(Math.random() * ((end - start) + 1));//随机选择一个作为标杆的数字

        //将标杆放在数组最后一位
//        System.out.println(arr.toString());
//        System.out.println(arr[index]);
//        System.out.println(arr[end]);
        char tmp = arr[index]; arr[index] = arr[end]; arr[end] = tmp;

        int small = start - 1;//small用来存储从右到左第一个小于标杆的数字的下标
        for(index = start; index < end; index++){
            if(arr[index] < arr[end]){//如果小于标杆
                small++;//更新第一个小的
                if(small != index){//如果当前遍历的不是第一个小的
                    tmp = arr[index];arr[index] = arr[small];arr[small] = tmp;//将当前遍历的数字放在第一个小的位置上

                }
            }
        }

        //由于small指示的是从右到左第一个小于标杆的,而此时标杆还放在数组最后,因此,应该将标杆放在small后面一位。
        small++;
        tmp = arr[small];arr[small] = arr[end]; arr[end] = tmp;

        return small;//返回位置为所选择的标杆最后的位置

    }

    public void QuickSort(char[] arr, int start, int end){

        if(start == end){
            return;
        }
        int index = Partition(arr, start, end);

        if(index > start){
            QuickSort(arr, start, index - 1);
        }
        if(index < end){
            QuickSort(arr, index + 1, end);
        }
    }

算法分析

时间复杂度:最好O(nlog2n),平均O(nlog2n),最坏:O(n2)

空间复杂度O(log2n)

快速排序是所有排序算法中最好的.

<<选择排序>>

简单选择排序

思路:

简单选择排序采用最简单的选择方式,从头至尾顺序扫描序列,找出最小的一个记录,和第一个记录交换,接着从剩下的记录中继续这种选择和交换,最终使序列有序.

代码:

    public static void SimpleSelectSort(int[] arr){

        if(arr == null || arr.length == 0){
            System.err.println("ERROR INPUT");
            return;
        }

        for(int i = 0; i < arr.length; i++){
            int temp = arr[i];

            int min = arr[i];
            int idx = i;
            for(int j = i; j < arr.length; j++){
                if(arr[j] < min){
                    min = arr[j];
                    idx = j;
                }
            }

            arr[idx] = temp;
            arr[i] = min;

        }
    }

算法分析:

时间复杂度:O(n2)

空间复杂度:O(1)

堆排序

思路:

将序列调整成一个堆.

代码:

/**
     * 本函数完成对在数组R[low]到R[high]范围内对在位置low上的结点进行调整
     * @param arr
     * @param low
     * @param high
     */
    public static void shift(int[] arr, int low, int high){
        if(arr == null || arr.length == 0){
            return;

        }

        int i = low;
        int j = 2 * i;//arr[j]是arr[i]的左孩子结点
        int temp = arr[i];
        while(j <= high){
            if(j < high && arr[j] < arr[j+1]){//若右孩子较大,则把j指向右孩子
                j++;                        //j变为2*i+1
            }

            if(temp < arr[j]){//将R[j]调整到双亲位置上
                arr[i] = arr[j];
                i = j;
                j = 2 * i;
            }else{
                break;//调整结束
            }
        }

        arr[i] = temp;//被调整结点的值放入最终位置
    }

    /**
     * 堆排序函数
     * @param arr
     */

    public static void heapSort(int[] arr){
        if(arr == null || arr.length == 0){//输入参数的非法性检查
            System.err.println("ERROR INPUT");
            return;
        }

        int i;
        int temp;
        int n = arr.length;

        for(i = n / 2; i >= 0; i--){//建立初始堆
            shift(arr, i, n-1);
        }

        for(i = n-1; i >= 1; i--){//进行n-1次循环完成堆排序
            temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            shift(arr, 0, i-1);//在减少了1个元素的无序序列中进行调整
        }
    }

算法分析:

时间复杂度:O(nlog2n)

空间复杂度:O(1)

归并排序

二路归并排序

思路

初始状态是每个元素是一个子序列,然后两两合并,形成了几个两个元素的子序列,....,依次合并下去,直到合并为一个有序序列.

代码

算法分析

时间复杂度:O(nlog2n)

空间复杂度:O(n)

基数排序

算法分析

时间复杂度:O(d(n+rd))

空间复杂度:O(rd)

排序算法的对比

时间复杂度:

"快些以O(nlog2n)的速度归队"

即快,希,归,堆都是O(nlog2n),其他都是O(n2),基数排序例外,是O(d(n+rd))

空间复杂度:

快排O(log2n)

归并O(n)

基数O(rd)

其他O(1)

稳定性

"心情不稳定,快些找一堆朋友聊天吧"

即不稳定的有:快,希,堆

其他性质

  1. 直接插入排序,初始基本有序情况下,是O(n)
  2. 冒泡排序,初始基本有序情况下,是O(n)
  3. 快排在初始状态越差的情况下算法效果越好.
  4. 堆排序适合记录数量比较大的时候,从n个记录中选择k个记录.
  5. 经过一趟排序,元素可以在它最终的位置的有:交换类的(冒泡,快排),选择类的(简单选择,堆)
  6. 比较次数与初始序列无关的是:简单选择与折半插入
  7. 排序趟数与原始序列有关的是:交换类的(冒泡和快排)
时间: 2024-08-19 11:31:55

数据结构:排序算法的相关文章

黑马程序员——数据结构排序算法总结

-----------android培训.java培训.java学习型技术博客.期待与您交流!------------ 下面是几个网上常见的总结图: 有些不同之处:集中在希尔排序的时间复杂度.快速归并的空间复杂度上 个人总结口诀: 选择N方-->选择排序的最好最坏平均都N方 插入冒泡最好N-->插入冒泡的最好是N,其他是N方 归并堆n乘logN-->归并希尔堆的最好最坏平均都是n乘logN 快速最坏N方-->快速排序的最坏是N方,其他是n乘logN 快速选择希尔堆不稳定-->

数据结构排序算法Java实现

闲的无聊又拿起了大学的数据结构的书看起来 <数据结构(c语言版)>严蔚敏 吴伟民编著. 里面有几个排序算法,感觉挺好玩的,就想着写出来玩玩. package test.sort; /** * @Title: TODO * @Description: TODO * @author: * @date: 2014-8-10 上午11:20:43 * */ public class quickSort { private static int datas[] = {23,42,12,45,56,63,

数据结构——排序算法总结

排序(Sorting)就是将一组对象依照规定的次序又一次排列的过程,排序往往是为检索而服务的.它是数据处理中一种非常重要也非经常常使用的运算.比如我们日常学习中的查字典或者书籍的文件夹.这些都事先为我们排好序,因此大大减少了我们的检索时间,提高工作效率. 排序可分为两大类: 内部排序(Internal Sorting):待排序的记录所有存放在计算机内存中进行的排序过程: 外部排序(External Sorting):待排序的记录数量非常大,内存不能存储所有记录.须要对外存进行訪问的排序过程. 外

数据结构-排序算法总结

排序算法 算法分析 算法稳定性 如果一种排序算法不会改变关键码值相同的记录的相对顺序,则称为稳定的(stable) 不稳定的算法在某种条件下可以变为稳定的算法,而稳定的算法在某种条件下也可以变为不稳定的算法.例如,对于冒泡排序算法,原本是稳定的排序算法,如果将记录交换的条件改成a[j].key>=a[j+1].key,则两个相等的记录就会交换位置.再如,快速排序原本是不稳定的排序方法,但若待排序记录中只有一组具有相同关键码的记录,而选择的轴值恰好是这组相同关键码中的一个,此时的快速排序就是稳定的

数据结构排序算法之快速排序

排序算法包括很多种,其中快速排序是其中一种比较快的排序算法,今天就来介绍一下: 快速排序的基本实现思想就是将当前待排序列分成两个部分.一个值.一个值:就是选定出一个值作为被比较的元素.两个部分:所有比该被选定元素大的部分都去该元素的右边,所有比被选定元素小的部分都去该元素的左边.这样我们就确定了该元素在这个待排序列中的位置,其实也就是我们已经将这个元素“排好了”. 那么,怎么才能完成一次的快速排序呢? 我们选定一个被比较的元素,一般都是选第一个,即数组中第一个元素作为val,然后我们给出两个指针

数据结构排序算法之选择排序

今天继续介绍一种排序算法:选择排序. 选择排序的基本思想就是从待排序列中选择出最小的,然后将被选出元素和序列的第一个元素互换位置(当前默认是升序排列),则互换完成后第一个元素就是整个序列的最小的元素,则一次选择排序结束.然后我们从剩下的子序列中选择出最小的,然后将该被选出来的元素和该子序列的第一个元素(即整个序列的第二个元素)互换位置,则当前整个序列的第二个元素就是当前序列中的次最小值,第二次选择排序结束.以此类推,直到该待排序列只剩下一个元素后,则整个序列有序. 具体过程如下图所示: 下面就不

自己动手实现数据结构——排序算法1(冒泡、插入、归并、简单选择)(C++实现)

冒泡排序 冒泡排序作为最简单的排序算法.两行for循环即可搞定. 步骤:一.从前到后依次比较相邻两个数大小,若是前面比后面大则将两个数交换位置,这样第一轮最大的一个数便会被交换到最后面. 二.重复一的步骤依次比较(但是最后一个数不需要参与比较,因为第一轮已经选出它最大),选出倒数第二大的. .... 三.直到所有的数都不需要比较则排序成功 例子就不举了,直接实现: buddle.cc #include<iostream> #include<vector> using namespa

数据结构排序算法总结

在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,该排序方法是稳定的:若具有相同关键字的记录之间的相对次序发生改变,则称这种排序方法是不稳定的.即所有相等的数经过某种排序方法后,仍能保持它们在排序之前的相对次序,则说这种排序算法是稳定的,反之,就是不稳定的. 稳定的排序算法如下表所示: 稳定的排序 时间复杂度 空间复杂度 冒泡排序(bubble sort) 最差.平均都是O(n^2),最好是O(n) 1 插入排序(insertion sort

数据结构-排序算法

排序的定义 排序 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的任意序列,重新排列成一个按关键字有序的序列. 排序分为内部排序和外部排序 内部排序 指的是待排序记录存放在计算机存储器中进行的排序过程 外部排序 指的是待排序记录的数量很大,以致内存一次不能容纳全部记录,在排序过程中尚需对外存进 行访问的排序过程. 下面只介绍内部排序: 分类 插入排序:直接插入排序.二分法插入排序.希尔排序. 选择排序:简单选择排序.堆排序. 交换排序:冒泡排序.快速排序. 归并排序 基数排序 对

数据结构-排序算法总览

1.排序 通常将数据元素称为记录.显然我们输入的是一个记录集合,排序输出的也是一个记录集合.可以将排序看成线性表的一种操作. 排序的依据是关键词之间的大小关系,对同一记录集合,针对不同的关键字进行排序,可以得到不同的序列. 2.影响排序算法性能的几个要素 1)时间性能:尽可能少的关键字比较次数和记录移动次数 2)辅助空间:使用内存较小 3)算法的复杂度: 3.排序算法的种类 简单分为两大类: 简单算法:冒泡排序,简单选择排序,直接插入排序:改进算法:希尔排序,堆排序,归并排序,快速排序: 根据时