最全的数据结构排序算法实现及比较

冒泡排序

类似暴力破解,1 – n 个,每个都比较一次。完成排序

public void sort(int[] arr) {
    int len = arr.length;
    for (int i = 0; i < len; i++) {
        for (int j = i + 1; j < len - 1; j++) {
            if (arr[i] > arr[j]) {
                SwapUtil.swap(arr, i, j);
            }
        }
    }
}

选择排序

[ 排序完毕 | 未排序] 每次从未排序的找一个最小的放入到排序完毕的后边

public void sort(int[] arr) {
    int len = arr.length;
    for (int i = 0; i < len; i++) {
        int index = findMinIndex(arr, i);
        if (index !=  -1) {
            SwapUtil.swap(arr, i, index);
        }
    }
}
 
public int findMinIndex(int[] arr, int begin) {
    int len = arr.length;
    int index = -1, elem = arr[begin];
    for (; begin < len; begin++) {
        if (arr[begin] < elem) {
            index = begin;
            elem = arr[begin];
        }
    }
    return index;
}
堆排序

堆排序

先进行堆的构建,再进行堆的调整

@Override
public void sort(int[] arr) {
    int len = arr.length;
    sort(arr, len);
}
 
private void sort(int[] arr, int len) {
    buildMaxHeap(arr, len);
    adjust(arr, len);
}
 
private void adjust(int[] arr, int len) {
    for (int i = len - 1; i > 0; i--) {
        SwapUtil.swap(arr, 0, i);
        adjustHeap(arr, 0, i);
    }
}
 
private void buildMaxHeap(int[] arr, int len) {
    // 这里索引从 0 开始,所以最后一个非叶子子节点 array.length / 2 - 1;
    for (int i = len / BUILD_HEAP_SEPARATED - 1; i >= 0; i--) {
        adjustHeap(arr, i, len);
    }
    System.out.println("build heap : " + Arrays.toString(arr));
}
 
private void adjustHeap(int[] arr, int i, int length) {
    // 先把当前元素取出来,因为当前元素可能要一直移动
    int temp = arr[i];
    // 从左孩子开始遍历 ( 2i + 1)
    for (int k = 2 * i + 1; k < length; k = 2 * k + 1) {
        // 若右孩子存在,且右孩子大于左孩子
        if (k + 1 < length && arr[k] < arr[k + 1]) {
            // 转移到右孩子
            k++;
        }
        // 如果发现结点(左右子结点)大于根结点,则进行值的交换
        if (arr[k] > temp) {
            SwapUtil.swap(arr, i, k);
            // 如果子节点更换了,则以子节点为根的子树会受到影响,
     // 所以,循环对子节点所在的树继续进行判断
            i  =  k;
        } else {
            //不用交换,直接终止循环
            break;
        }
    }
}

希尔排序

这里采用数组长度一半作为希尔增量进行排序,每次减少一半,知道增量为1.排序完毕。

 @Override
public void sort(int[] arr) {
    int step = arr.length / 2;
    for ( ; step > 0; step /= 2) {
        for (int i = step; i < arr.length; i++) {
            int value = arr[i];
            int j;
            // 跳跃的插入, 因为增量的存在,所以,后移时,是当前增量后移
            for (j = i - step; j >= 0 && arr[j] > value; j -= step) {
                arr[j + step] = arr[j];
            }
            arr[j + step] = value;
        }
    }
 
}

插入排序

类似于选择排序,分为【排序 | 未排序区域】每次从未排序区域选取一个,再排序区域寻找位置,然后后移交换。

@Override
public void sort(int[] arr) {
    int len = arr.length;
    for (int i = 1; i < len; i++) {
        int elem = arr[i];
        int index = getIndex(arr, i, elem);
        if (index != i) {
            retreat(arr, index, i);
            arr[index] = elem;
        }
    }
}
 
/**
 * 获取插入排序所在索引
 * @param arr 数组
 * @param limit 已排序区间上界
 * @param elem 待排序元素
 * @return 要插入的数组
 */
private int getIndex(int[] arr, int limit, int elem) {
    for (int i = 0; i < limit; i++) {
        if (elem < arr[i]) {
            return i;
        }
    }
    return limit;
}
 
/**
 * 将数组内一段元素后移
 * @param arr 数组
 * @param begin 区间下界
 * @param end 区间上界
 */
private void retreat(int[] arr, int begin, int end) {
    while(end > begin) {
        arr[end] = arr[end - 1];
        end--;
    }
}

二路归并排序

@Override
public void sort(int[] arr) {
    mergeSort(arr, 0, arr.length - 1);
}
 
public void mergeSort(int[] arr, int left, int right) {
    if (left < right) {
        int mid = (left + right) / 2;
        mergeSort(arr, left, mid);
        mergeSort(arr, mid + 1, right);
        merge(arr, left, mid, right);
    }
}
 
public void merge(int[] arr, int left, int mid, int right) {
    int[] temp = new int[arr.length];
    int leftIndex = left, rightIndex = mid + 1, tempIndex = left;
    while (leftIndex <= mid && rightIndex <= right) {
        if (arr[leftIndex] < arr[rightIndex]) {
            temp[tempIndex++] = arr[leftIndex++];
        } else {
            temp[tempIndex++] = arr[rightIndex++];
        }
    }
    while (leftIndex <= mid) {
        temp[tempIndex++] = arr[leftIndex++];
    }
    while(rightIndex <= right) {
        temp[tempIndex++] = arr[rightIndex++];
    }
    // 将归并结果归坏到原数组中
    while (left <= right) {
        arr[left] = temp[left++];
    }
}

快速排序

设数组第一个元素为基准,

第一步:数组中所有元素,小于 基准 放到左边,大于 基准 放到右边,此时数组分为两部分,对于基准来说已经处于它应处的位置

第二步,对左右两半数组继续执行第一步,递归完毕,数组有序

时间复杂度: O(n*log2n) – 空间复杂度: good: O(log2n) – bad: O(n)

@Override
public void sort(int[] arr) {
    int len = arr.length;
    sort(arr, 0, len - 1);
}
 
private void sort(int[] arr, int left, int right) {
    if (left < right) {
        int mid = partition(arr, left, right);
        sort(arr, left, mid - 1);
        sort(arr, mid + 1, right);
    }
}
 
private int partition(int[] arr, int left, int right) {
    int sentry = arr[left];
    while (left < right) {
        while (left < right && arr[right] >= sentry) {
            right--;
        }
        arr[left] = arr[right];
        while(left < right && arr[left] <= sentry) {
            left++;
        }
        arr[right] = arr[left];
    }
    arr[left] = sentry;
    return left;
}

排序比较

排序方法 最好情况 最坏情况 平均情况 空间复杂度 稳定性
直接插入排序 O(n) O(n^2) O(n^2) O(1) 稳定
折半插入排序 O(nlong2n) O(n^2) O(n^2) O(1) 稳定
希尔排序 O(n^1.3) O(1) 不稳定
冒泡排序 O(n) O(n^2) O(n^2) O(1) 稳定
简单选择排序 O(n) O(n^2) O(n^2) O(1) 不稳定
快速排序 O(nlog2n) O(n^2) O(nlog2n) O(nlog2n) 不稳定
堆排序 O(nlog2n) O(nlog2n) O(nlog2n) O(1) 不稳定
归并排序 O(nlog2n) O(nlog2n) O(nlog2n) O(n) 稳定
基数排序 O(d(n+rd)) O(d(n+rd)) O(d(n+rd)) O(n+rd) 稳定

125jz网原创文章。发布者:江山如画,转载请注明出处:http://www.125jz.com/8811.html

(1)
江山如画的头像江山如画管理团队
上一篇 2020年10月12日 上午9:35
下一篇 2020年10月14日 上午9:13

99%的人还看了以下文章

  • Python 8大知识点——附详细实例代码。

    目录 1. for – else 2.lambda函数 3.列表推导式 4.列表索引的各种骚操作 5.三元表达式 6.巧用断言assert 7.while语句 8.with – as 1. for – else 什么?不是 if 和 else 才是原配吗?No,你可能不知道,else 是个脚踩两只船的家伙,for 和 else 也是一对,而且是合法的。十大装…

    2023年1月14日
    1.9K0
  • MVC详解:模型(Model)-视图(View)-控制器(Controller)

    MVC(模型-视图-控制结构)是软件开发中常用的一种架构模式。它强制性的将输入、处理和输出分开。使应用程序被分成三个核心部件:模型 (Model)、视图(View)和控制(Controller)。它们各自处理自己的任务,有效地分离存储数据和展示数据功能模块以降低它们之间的耦合度。 MVC体系结构: 模型层主要负责保存和访问业务数据,执行业务逻辑和操作。这一层…

    2020年2月23日
    7.4K0
  • 最清楚的过拟合(Overfitting)、欠拟合讲解

    问题的产生 当我们构建模型时,总会希望假设空间参数尽可能多,系统越复杂,拟合得越好嘛!我们还希望我们的优化算法能使我们的模型产生的损失函数的值尽可能小(即我们的假设空间能够贴合每一个训练样本点)。但这样真的好吗?奥卡姆剃刀貌似又胜利了。然而假设我们的模型达成了上述的情况,有很大概率产生一个ML界非常令人头疼的一件事:过拟合(Overfitting)。 欠拟合…

    2022年9月21日
    10.0K0
  • 跟永哥学MVC:jsp+javabean+servlet实现求圆的面积

    上一节课我们通过一个案例三种实现,教你理解Jsp、javabean、Servlet(精),今天我们仍然通过同一个案例求圆的面积,使用MVC:jsp+javabean+servlet来实现,深入理解MVC及Jsp、javabean、Servlet的分工和使用。 r5.jsp <form action=”servletCircle” Method=”pos…

    2018年2月22日
    8.3K0
  • 9个要点让你成为优秀的Java程序员

    文章介绍了要成为优秀Java程序员的9个要点,掌握了这些要点,会让你在众多Java开发人员中脱颖而出。

    2022年12月1日
    1.5K0
  • 简!python中安装pip的方法

     pip的安装 打开cmd,输入以下命令安装pip: python -m ensurepip –default-pip 出现如下图所示,代表pip安装成功: 查看pip版本 pip –version 更新pip版本 python -m pip install –upgrade pip 安装库 例如安装pyyaml库,打开cmd输入以下命令: pip i…

    2023年5月18日
    16.9K0

发表回复

登录后才能评论