💪
AndroidCollect
  • 写在前面
  • 计算机基础
    • 计算机组成原理
    • 算法
      • 查找
        • 二分查找
      • 排序
        • 简单排序
        • 高级排序
        • 特殊排序
      • 海量数据
      • 思想
        • 贪心
        • 分治
        • 动态规划
        • 回溯
      • 哈希算法
    • 数据结构
      • 队列
        • 知识点
        • 相关题目
          • 用两个栈实现队列
          • 实现循环队列
          • 用链表实现队列
          • 用数组实现队列
      • 栈
        • 相关算法题目
          • 用链表实现栈
          • 用数组实现栈
      • 链表
        • 知识点梳理
        • 相关算法题目
          • 删除倒数第n个结点
          • 合并两个有序链表
          • 检测单链表是否有环
          • 获取中间结点
          • 反转链表
      • 跳表
      • 哈希表
      • 树
        • 二叉树
        • 二叉查找树
        • AVL 树
        • Trie 树
        • 红黑树
      • 堆
        • 存储
        • 堆的应用
      • 图
    • 网络
      • 应用层协议
        • DNS
        • HTTP
        • HTTPS
      • 传输层协议
        • TCP
        • UDP
      • 输入网址后发生了什么
    • 操作系统
      • 内存
    • 数据库
  • 软件工程
    • 编程思想
    • 设计模式
      • 状态模式
      • 装饰器模式
      • 代理模式
      • 责任链模式
      • 建造者模式
      • 单例模式
      • 观察者模式
  • Java
    • 基础
    • 异常
    • 并发编程
      • ThreadLocal
      • 线程池
      • 理解 volatile
      • AbstractQueuedSynchronizer
    • 集合
      • LinkedHashMap 源码
      • HashMap 源码
    • 注解
    • 反射
      • JDK 动态代理
    • JVM
      • 自动内存管理机制
      • Class 文件格式
      • 类加载机制
      • Java 内存模型(JMM)
      • 字节码指令
      • HotSpot 虚拟机实现细节
    • 源码与原理
    • 各版本主要特性
  • Android
    • 基础组件
      • Context
      • Activity
        • 生命周期
        • 启动模式与任务栈
        • 启动流程
      • Service
      • ContentProvider
      • BroadcastReceiver
      • Fragment
      • View
        • 常用控件问题总结
          • RecyclerView
          • ViewPager2
        • CoordinatorLayout
        • SurfaceView
        • 事件分发
        • 绘制流程
        • 自定义 View
        • Window
    • 数据存储
      • 存储结构
      • Sqlite
      • 序列化
      • SharedPreferences
    • 资源
      • 图片加载
    • 动画
      • 属性动画
    • 线程和进程
      • Binder 机制
      • 跨进程通信
        • AIDL
    • 内部原理
      • 消息循环机制
      • Binder
      • Window
      • SparseArray
      • ArrayMap
      • RecyclerView
      • App 启动流程
    • 性能优化
      • 内存
        • 内存使用优化
        • 内存泄漏
      • 启动优化
      • 缩减包大小
      • 布局优化
      • ANR
    • 打包构建
      • dex 文件
      • APK 打包流程
      • APK 签名流程
    • 架构
      • 运行时
      • Android 系统架构
      • 应用项目架构
    • 开源框架源码或原理
      • RxJava
        • 使用笔记
        • 源码解析
      • Retrofit
      • ButterKnife
      • BlockCanary
      • LeakCanary
      • OkHttp
      • 图片加载
        • Glide
        • Picasso
    • 碎片化处理
      • 屏幕适配
    • 黑科技
      • 热修复
    • Jetpack
      • Lifecycle
      • Room
      • WorkManager
    • 新动态
      • AndroidX
      • 各系统版本特性
  • 开发工具
    • 正则表达式
    • ADB
    • Git
  • Kotlin
  • Flutter
  • 关于作者
  • 致谢
由 GitBook 提供支持
在本页
  • 归并排序
  • 快速排序
  • 希尔排序
  • 堆排序

这有帮助吗?

  1. 计算机基础
  2. 算法
  3. 排序

高级排序

时间复杂度为O(n^2)的排序算法

归并排序

  public class MergeSort implements ISort {
    @Override
    public void sort(int[] arr) {
        mergeSortRecur(arr, 0, arr.length - 1);
    }

    /**
     * 递归实现的归并排序
     */
    private void mergeSortRecur(int[] arr, int start, int end) {
        if (start >= end) {
            return;
        }
        int middle = (start + end) / 2;
        mergeSortRecur(arr, start, middle);
        mergeSortRecur(arr, middle + 1, end);
        merge(arr, start, middle, end);

    }

    private void merge(int[] arr, int start, int middle, int end) {

        int i = start;
        int j = middle + 1;
        int k = 0;

        int[] tmp = new int[end - start + 1];

        while (i <= middle && j <= end) {
            if (arr[i] > arr[j]) {
                tmp[k++] = arr[j++];
            } else {
                tmp[k++] = arr[i++];
            }
        }

        //确定哪部分数组还有剩余
        int s = i <= middle ? i : j;

        while (k < tmp.length) {
            tmp[k++] = arr[s++];
        }

        for (int l = start; l <= end; l++) {
            arr[l] = tmp[l - start];
        }
    }
}

快速排序

public class QuickSort implements ISort {
    @Override
    public void sort(int[] arr) {
        if (arr == null || arr.length <= 1) {
            return;
        }

        quickSortRecur(arr, 0, arr.length - 1);
    }

    private void quickSortRecur(int[] arr, int start, int end) {
        if (start >= end) {
            return;
        }
        int p = partition(arr, start, end);
        //注意边界是 p-1 和 p+1,因为中间元素的最终位置已确定
        quickSortRecur(arr, start, p-1);
        quickSortRecur(arr, p + 1, end);
    }

    private int partition(int[] arr, int s, int t) {
        int pivot = arr[t];

        int i = s;
        //注意边界 j<t,是把最后一个元素之前的元素与其进行比较
        for (int j = s; j < t; j++) {
            if (arr[j] < pivot) {
                Util.swap(arr, j, i);
                i++;
            }
        }
        Util.swap(arr, i, t);
        return i;
    }
}

希尔排序

public class ShellSort implements ISort {
    @Override
    public void sort(int[] arr) {
        if (arr == null || arr.length == 0) {
            return;
        }

        int gap = arr.length / 2;
        while (gap > 0) {
            for (int i = gap; i < arr.length; i++) {
                //可以加一层判断减少执行时间
                int j = i - gap;
                int value = arr[i];
                for (; j >= 0 && arr[j] > value; j -= gap) {
                    Util.swap(arr, j, j + gap);
                }
                arr[j + gap] = value;
            }
            gap /= 2;
        }

    }
}

堆排序

堆排序过程主要分为两个步骤:建堆和排序 。

建堆

建堆的过程就是把原数据组织成一个堆。有两种思路:

  • 从第二个节点开始 ,按照插入的方式放入堆,然后自下向上进行调整

  • 从最后一个非叶子节点开始,使用自顶向下调整的方式,直到根节点


private static void buildHeap(int[] a, int n) {
  //从最后一个非叶子节点开始,使用自顶向下调整的方式,直到根节点
  for (int i = n/2; i >= 1; --i) {
    heapify(a, n, i);
  }
}

private static void heapify(int[] a, int n, int i) {
  while (true) {
    int maxPos = i;
    if (i*2 <= n && a[i] < a[i*2]) maxPos = i*2;
    if (i*2+1 <= n && a[maxPos] < a[i*2+1]) maxPos = i*2+1;
    if (maxPos == i) break;
    swap(a, i, maxPos);
    i = maxPos;
  }
}

排序

每次取堆顶元素与堆最后一个元素进行交换,然后将剩下的元素重新调整为堆,直到只剩一个元素,排序完成。

// n表示数据的个数,数组a中的数据从下标1到n的位置。
public static void sort(int[] a, int n) {
  buildHeap(a, n);
  int k = n;
  while (k > 1) {
    swap(a, 1, k);
    --k;
    heapify(a, k, 1);
  }
}

堆排序的时间复杂度为O(nlogn),不稳定。

与快速排序相比

  • 数据访问是跳跃性的,不能充分利用CPU缓存提升性能

  • 交换次数要多于快速排序(有序的数据堆化后反而无序了)

上一页简单排序下一页特殊排序

最后更新于5年前

这有帮助吗?

堆的结构可以查看。

建堆时间复杂度为O(n),推导过程见。

相关章节
专栏内容
有序数据堆化后变得更加无序