• 排序算法(Java实现)


    1. 冒泡排序

        冒泡排序属于交换排序。效率较低,适用小规模数据集。

        原理:循环遍历要排序的元素,依次比较两个相邻的元素,每次循环都找到一个最大(或最小)的数放到最后(或最前)。没有相邻元素需要交换时,说明已经排序完成。

        它是稳定排序 (即相等的两个元素,在排序后相对位置不会发生变化)。

    1. public static void bubbleSort(int[] arrData) {
    2. int temp;
    3. int count = 0;
    4. //控制循环次数
    5. for (int i = 0; i < arrData.length - 1; ++i) {
    6. for (int j = 0; j < arrData.length - 1 - i; ++j) {
    7. ++count;
    8. if (arrData[j] > arrData[j + 1]) {
    9. temp = arrData[j];
    10. arrData[j] = arrData[j + 1];
    11. arrData[j + 1] = temp;
    12. }
    13. }
    14. }
    15. System.out.println("比较次数:" + count);
    16. }

    改进算法1,记录本此循环有无数据交换,若无则表示数据已经有序,跳出循环。

    1. public static void bubbleSort1(int[] arrData) {
    2. int temp;
    3. int count = 0;
    4. boolean noChange;
    5. //控制循环次数
    6. for (int i = 0; i < arrData.length - 1; ++i) {
    7. noChange = true;
    8. for (int j = 0; j < arrData.length - 1 - i; ++j) {
    9. ++count;
    10. if (arrData[j] > arrData[j + 1]) {
    11. temp = arrData[j];
    12. arrData[j] = arrData[j + 1];
    13. arrData[j + 1] = temp;
    14. noChange = false;
    15. }
    16. }
    17. if (noChange) {
    18. break;
    19. }
    20. }
    21. System.out.println("比较次数:" + count);
    22. }

    改进算法2,改进算法1加上记录本次循环比较交换的最后位置,后面的元素是有序的,下次循环无需再比较最后位置元素之后的数据。

    1. public static void bubbleSort2(int[] arrData) {
    2. int temp;
    3. int count = 0;
    4. boolean noChange;
    5. int lastPos = arrData.length - 1;
    6. int comparePos = 0;
    7. //控制循环次数
    8. for (int i = 0; i < arrData.length - 1; ++i) {
    9. noChange = true;
    10. for (int j = 0; j < lastPos; ++j) {
    11. ++count;
    12. if (arrData[j] > arrData[j + 1]) {
    13. temp = arrData[j];
    14. arrData[j] = arrData[j + 1];
    15. arrData[j + 1] = temp;
    16. noChange = false;
    17. comparePos = j;
    18. }
    19. }
    20. lastPos = comparePos;
    21. if (noChange) {
    22. break;
    23. }
    24. }
    25. System.out.println("比较次数:" + count);
    26. }

    对数据{19,25,1,30,12,8,26,24,40,72},bubbleSort的比较次数为45次,bubbleSort1的比较次数为35次,bubbleSort2的比较次数为25次。

    2. 快速排序

        快速排序属于交换排序。基于分而治之策略,效率稍高。

        原理:每一趟排序将数据分割成左右两部分,其中左边的数据都比右边的数据小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程递归进行,最终整个数据变成有序。

        它是不稳定排序 (即相等的两个元素,在排序后相对位置可能发生变化)。

    1. public static void quickSort(int[] arrData, int left, int right) {
    2. if (left > right) {
    3. return;
    4. }
    5. //基准数
    6. int base = arrData[left];
    7. int i = left;
    8. int j = right;
    9. while (true) {
    10. //要先从右向左找
    11. while (i < j && base <= arrData[j]) {
    12. --j;
    13. }
    14. while (i < j && base >= arrData[i]) {
    15. ++i;
    16. }
    17. if (i >= j) break;
    18. int temp = arrData[i];
    19. arrData[i] = arrData[j];
    20. arrData[j] = temp;
    21. }
    22. //将基准数和小的数交换
    23. arrData[left] = arrData[i];
    24. arrData[i] = base;
    25. //左边排序
    26. quickSort(arrData, left, i - 1);
    27. //右边排序
    28. quickSort(arrData, j + 1, right);
    29. }
    3. 直接插入排序

        直接插入排序属于插入排序。适合数据个数小于20个的数据集

        原理:将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增1的有序表。一开始有序表就只有第一个数。

    1. public static void insertSort(int[] arrData) {
    2. //一开始有序表只有第一个数
    3. for (int i = 1; i < arrData.length; ++i) {
    4. //当前数比前一个小
    5. if (arrData[i] < arrData[i - 1]) {
    6. int temp = arrData[i];//保存当前数
    7. int j;
    8. //查找有序表里的插入位置
    9. for (j = i - 1; j >= 0 && temp < arrData[j]; --j) {
    10. arrData[j + 1] = arrData[j];//将前面的大数后移一格
    11. }
    12. arrData[j + 1] = temp;
    13. //System.out.println(Arrays.toString(arrData));
    14. }
    15. }
    16. }
    4. 希尔排序

        希尔排序属于插入排序,又称“缩小增量排序”,是直接插入排序更高效的改进版本。

        原理:把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。

    1. public static void shellSort(int[] arrData) {
    2. //遍历所有的步长
    3. for(int d = arrData.length/2; d > 0; d /= 2 ){
    4. //遍历所有元素
    5. for(int i = d; i < arrData.length; i++){
    6. //遍历本组中所有元素
    7. for(int j = i-d; j >= 0; j -= d){
    8. //如果当前元素大于加上步长后的那个元素
    9. if(arrData[j] > arrData[j+d]){
    10. int temp = arrData[j];
    11. arrData[j] = arrData[j+d];
    12. arrData[j+d] = temp;
    13. }
    14. }
    15. }
    16. }
    17. }
    5. 选择排序

        原理:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。

    1. public static void selectSort(int[] arrData){
    2. for(int i=0;i
    3. int minIndex = i;
    4. //把当前遍历的数和后面所有数依次进行比较,并记录最小数下标
    5. for(int j=i+1;j
    6. if(arrData[minIndex]>arrData[j]){
    7. minIndex = j;
    8. }
    9. }
    10. //如果最小的数和当前遍历的数下标不一致,说明下标为minIndex的数比当前遍历的数更小
    11. if(i != minIndex){
    12. int temp = arrData[i];
    13. arrData[i] = arrData[minIndex];
    14. arrData[minIndex] = temp;
    15. }
    16. }
    17. }

    6. 归并排序

        归并排序是建立在归并操作上的一种有效,稳定的排序算法。

        原理:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。也是基于分而治之策略。

    1. public static int[] mergeSort(int[] arrData, int low, int high) {
    2. if (low == high) {
    3. return new int[]{arrData[low]};
    4. }
    5. int mid = low + (high - low) / 2;
    6. int[] leftArrData = mergeSort(arrData, low, mid); //左有序数组
    7. int[] rightArrData = mergeSort(arrData, mid + 1, high); //右有序数组
    8. int[] newOut = new int[leftArrData.length + rightArrData.length]; //新有序数组
    9. int m = 0, i = 0, j = 0;
    10. while (i < leftArrData.length && j < rightArrData.length) {
    11. newOut[m++] = leftArrData[i] <= rightArrData[j] ? leftArrData[i++] : rightArrData[j++];
    12. }
    13. while (i < leftArrData.length)
    14. newOut[m++] = leftArrData[i++];
    15. while (j < rightArrData.length)
    16. newOut[m++] = rightArrData[j++];
    17. return newOut;
    18. }

    7. 桶排序

        桶排序(箱排序)是一种分布式排序。

        原理:将数据转换为另一种形式排序。通常用数组来表示每个桶,用原数据的值表示桶的索引。是一种空间换时间的算法。

    1. public static void bucketSort(int[] arrdata) {
    2. //注意数据需都>=0
    3. int max = getMaxOne(arrdata);
    4. int[] bucket = new int[max + 1];
    5. for (int i = 0; i < arrdata.length; ++i) {
    6. bucket[arrdata[i]]++;//计数
    7. }
    8. int pos = 0;
    9. for (int i = 0; i < bucket.length; ++i) {
    10. for (int j = 0; j < bucket[i]; ++j) {//同一个位置可能有几个相同数据值
    11. arrdata[pos++] = i;//i是原数据值
    12. }
    13. }
    14. }
    15. static int getMaxOne(int[] arrData) {
    16. int max = arrData[0];
    17. for (int i = 1; i < arrData.length; ++i) {
    18. if (arrData[i] > max) {
    19. max = arrData[i];
    20. }
    21. }
    22. return max;
    23. }

    8. 基数排序

        基数排序(radix sort)属于“分布式排序”(distribution sort)。也是用空间换时间的算法。

        原理:透过键值的部份信息,将要排序的元素分配至某些“桶”中,以达到排序的作用。如对整数数列排序中,先以个位为key分组,然后合并;再以十位为key分组,合并;以此类推,直到最大数的最高位。

    1. public static void radixSort(int[] arrData) {
    2. //d表示最大数字的位数有多少位
    3. int d = getLen(getMaxOne(arrData));
    4. int k = 0;
    5. int n = 1; //作除数
    6. int m = 1; //控制键值排序依据在哪一位,从第一位即个位开始
    7. int[][] temp = new int[10][arrData.length]; //数组的第一维表示可能的余数0-9
    8. int[] order = new int[10]; //数组order[i]用来表示该位是i的数的个数
    9. while (m <= d) {
    10. //根据余数来分组
    11. for (int i = 0; i < arrData.length; i++) {
    12. int lsd = ((arrData[i] / n) % 10);
    13. temp[lsd][order[lsd]] = arrData[i];
    14. order[lsd]++;
    15. }
    16. //合并分组
    17. for (int i = 0; i < 10; i++) {
    18. if (order[i] != 0) {
    19. for (int j = 0; j < order[i]; j++) {
    20. arrData[k] = temp[i][j];
    21. k++;
    22. }
    23. }
    24. order[i] = 0;
    25. }
    26. n *= 10;//作除数
    27. k = 0;
    28. m++;//位数+1
    29. }
    30. }
    31. static int getMaxOne(int[] arrData) {
    32. int max = arrData[0];
    33. for (int i = 1; i < arrData.length; ++i) {
    34. if (arrData[i] > max) {
    35. max = arrData[i];
    36. }
    37. }
    38. return max;
    39. }
    40. static int getLen(int v) {
    41. return (v + "").length();
    42. }

    9. 堆排序

        原理:堆排序首先要构造堆结构。堆结构是一个完全二叉树。完全二叉树指的是,若设二叉树的深度为n,除第 n 层外,其它各层 (1~n-1) 的结点数都达到最大个数,第 n 层所有的结点都连续集中在最左边。完整的堆排序经过反复的两个步骤:构造堆结构和堆排序输出(根节点)。

    1. public static void heapSort(int[] arrData) {
    2. int size = arrData.length;
    3. int i;
    4. //将n个元素建堆
    5. for (i = size / 2 - 1; i >= 0; i--) {//只需循环非叶节点
    6. heapCompare(arrData, i, size);
    7. }
    8. int k, t;
    9. for (i = size - 1; i > 0; i--) {
    10. //根节点为最大值,放到数组后面
    11. t = arrData[0];
    12. arrData[0] = arrData[i];
    13. arrData[i] = t;
    14. k = 0;
    15. heapCompare(arrData, k, i);
    16. }
    17. }
    18. static void heapCompare(int[] arrData, int i, int total) {
    19. //i为非叶节点
    20. int j;
    21. while (2 * i + 1 < total) {//第i个节点有子树
    22. j = 2 * i + 1; //左子节点
    23. if ((j + 1) < total) {//存在右子节点
    24. if (arrData[j] < arrData[j + 1])//若左边小于右边
    25. j++;//指向右子节点
    26. }
    27. if (arrData[i] < arrData[j]) {//j为 i节点的子节点
    28. int t = arrData[i]; //交换数据
    29. arrData[i] = arrData[j];
    30. arrData[j] = t;
    31. i = j;//堆被破坏,需重新调整子树
    32. } else {//堆未破坏,无需调整
    33. break;
    34. }
    35. }
    36. }

    10. 数据比较

    稳定?原地?最好最坏平均空间说明
    冒泡排序O(n)O(n²)O(n²)O(1)
    插入排序O(n)O(n²)O(n²)O(1)
    归并排序O(nLogn)O(nLogn)O(nLogn)O(n)需额外空间
    桶排序O(n+k)O(n²)O(n²)O(n*k)k为桶总数
    基数排序O(d(n+r))O(d(n+r))O(d(n+r))O(n+r)d是关键码个数,r为关键码的最大值
    快速排序O(nLogn)O(n²)O(nLogn)O(Logn)
    希尔排序O(n)O(n²)O(nLogn)O(1)
    选择排序O(n²)O(n²)O(n²)O(1)最低效
    堆排序O(nLogn)O(nLogn)O(nLogn)O(1)

  • 相关阅读:
    python报错 UnicodeDecodeError
    关于“支付测试”相关的测试内容
    @Elasticsearch之深度应用及原理剖析--文档搜索机制剖析
    11月外贸新规
    Web攻防01-ASP应用相关漏洞-HTTP.SYS&IIS短文件&文件解析&ACCESS注入
    RecyclerView嵌套布局,导致RecyclerView复用失效 解决
    Python-简介
    【GAMES101 作业3】渲染小奶牛+使用.obj模型+双线性插值+踩坑总结
    Spark【RDD编程(二)RDD编程基础】
    【二分】Pythagorean Triples—CF1487D
  • 原文地址:https://blog.csdn.net/myepicure/article/details/131854570