排序算法之冒泡-快速-计数-桶-基数-堆Java版

上篇排序算法之插入-希尔-归并Java版:https://blog.csdn.net/u010597819/article/details/86646305

冒泡排序

package org.gallant.algorithm;

import static org.gallant.algorithm.SortUtil.println;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @author 会灰翔的灰机
 * @date 2020/1/19
 */
public class BubbleSort {

    public static void bubbleSort(int[] data) {
        int size = data.length;
        while (size > 1) {
            for (int i = 0; i < size - 1; i++) {
                int left = data[i];
                int right = data[i + 1];
                if (left > right) {
                    data[i] = right;
                    data[i + 1] = left;
                }
            }
            size--;
        }
    }

    public static void main(String[] args) {
        int[] array = SortUtil.randomArray(9);
        println(array);
        bubbleSort(array);
        println(array);
    }

}

快速排序

package org.gallant.algorithm;

import static org.gallant.algorithm.SortUtil.println;

/**
 * @author 会灰翔的灰机
 * @date 2020/1/19
 */
public class QuickSort {

    public static void quickSort(int[] data, int start, int end) {
        int pivotIndex = partitioning(data, start, end);
        if (pivotIndex > -1) {
            quickSort(data, start, pivotIndex);
            quickSort(data, pivotIndex, end);
        }
    }

    public static int partitioning(int[] data, int start, int end) {
        int pivot = data[start];
        int i = end, j = start + 1;
        while (i >= j) {
            int right = data[i];
            int left = data[j];
            // 相等的值放在右边子序列中
            boolean rightLesserPivot = right < pivot;
            boolean leftGreaterPivot = left >= pivot;
            // 哨兵i大于基准值,继续移动
            if (!rightLesserPivot) {
                i--;
            } else {
                // 哨兵j小于基准值,并且哨兵i已经发现大于基准值的值时,移动哨兵j
                if (!leftGreaterPivot) {
                    j++;
                }
            }
            if (leftGreaterPivot && rightLesserPivot) {
                // 哨兵i与哨兵j相遇前找到了比基准值大,比基准值小的数值,交换他们的位置
                swap(data, left, j, right, i);
                i--;
                j++;
            }
            // 哨兵i与哨兵j相遇
            if (i == j) {
                boolean isLesserPivot = data[i] < pivot;
                if (isLesserPivot) {
                    swap(data, pivot, start, data[i], i);
                }
                println(data);
                return i;
            }
        }
        return -1;
    }

    public static void swap(int[] data, int leftValue, int leftIndex, int rigthValue, int rightIndex){
        data[rightIndex] = leftValue;
        data[leftIndex] = rigthValue;
    }

    public static void main(String[] args) {
        int[] array = SortUtil.randomArray(15);
        println(array);
        // 错误的理解。。。代码有问题,正解见quickSort2方法
        quickSort(array, 0, array.length - 1);
        println(array);
    }

	private static void quickSort2(int[] arr, int low, int high) {

    if (low < high) {
      // 找寻基准数据的正确索引
      int index = getIndex(arr, low, high);

      // 进行迭代对index之前和之后的数组进行相同的操作使整个数组变成有序
      //quickSort(arr, 0, index - 1); 之前的版本,这种姿势有很大的性能问题,谢谢大家的建议
      quickSort2(arr, low, index - 1);
      quickSort2(arr, index + 1, high);
    }

  }

  private static int getIndex(int[] arr, int low, int high) {
    // 基准数据
    int tmp = arr[low];
    while (low < high) {
      // 当队尾的元素大于等于基准数据时,向前挪动high指针
      while (low < high && arr[high] >= tmp) {
        high--;
      }
      // 如果队尾元素小于tmp了,需要将其赋值给low
      arr[low] = arr[high];
      // 当队首元素小于等于tmp时,向前挪动low指针
      while (low < high && arr[low] <= tmp) {
        low++;
      }
      // 当队首元素大于tmp时,需要将其赋值给high
      arr[high] = arr[low];

    }
    // 跳出循环时low和high相等,此时的low或high就是tmp的正确索引位置
    // 由原理部分可以很清楚的知道low位置的值并不是tmp,所以需要将tmp赋值给arr[low]
    arr[low] = tmp;
    return low; // 返回tmp的正确位置
  }

}

计数排序

package org.gallant.algorithm;

import static org.gallant.algorithm.SortUtil.print;
import static org.gallant.algorithm.SortUtil.println;

/**
 * @author 会灰翔的灰机
 * @date 2020/1/20
 */
public class CountingSort {

    public static void countingSort(int[] data) {
        int max = Integer.MIN_VALUE,min = Integer.MAX_VALUE;
        // 1. 查找最大值、最小值
        for (int i = 0; i < data.length; i++) {
            int currentValue = data[i];
            if (currentValue > max) {
                max = currentValue;
            }
            if (currentValue < min) {
                min = currentValue;
            }
        }
        // 2. 将数据根据最小值映射放入对应的桶内(index下标处)
        println("max:"+max+",min:"+min);
        int[] count = new int[max - min + 1];
        for (int i = 0; i < data.length; i++) {
            int currentValue = data[i];
            print(currentValue+",");
            count[currentValue - min] += 1;
        }
        println("");
        println(count);
        // 3. 根据计数桶还原数据到原数据中。计数桶中的数据由于映射的算法可知是有序的
        int currentDataIndex = 0;
        for (int i = 0; i < count.length; i++) {
            int cnt = count[i];
            if (cnt > 0) {
                for (int j = 0; j < cnt; j++) {
                    data[currentDataIndex] = min + i;
                    currentDataIndex++;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] array = SortUtil.randomArray(11);
        println(array);
        countingSort(array);
        println(array);
    }

}

桶排序

package org.gallant.algorithm;

import static org.gallant.algorithm.SortUtil.println;

import java.util.Arrays;
import java.util.Objects;

/**
 * @author 会灰翔的灰机
 * @date 2020/1/20
 */
public class BucketSort {

    public static void bucketSort(int[] array) {
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        // 1. 查找 数字长度 最大值、最小值
        for (int currentValue : array) {
            int len = getIntegerLength(currentValue);
            if (len > max) {
                max = len;
            }
            if (len < min) {
                min = len;
            }
        }
        // 2. 将数据根据数字长度以及最小长度,放入对应的桶中
        println("max:"+max+",min:"+min);
        Integer[][] count = new Integer[max - min + 1][array.length];
        for (int i = 0; i < array.length; i++) {
            int currentValue = array[i];
            Integer[] bucket = count[getIntegerLength(currentValue) - min];
            for (int j = 0; j < bucket.length; j++) {
                if (bucket[j] == null) {
                    bucket[j] = currentValue;
                    break;
                }
            }
        }
        println(count);
        // 3. 根据映射函数可知,桶的下标大的桶中的所有数据大于下标小的桶中的数据
        // 所以将每个桶排序后直接拼接结果便可以得到全局有序的集合
        int currentDataIndex = 0;
        for (int i = 0; i < count.length; i++) {
            Integer[] bucketObj = count[i];
            if (bucketObj.length > 0) {
                int[] bucket = Arrays.stream(bucketObj).filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();
                Sorts.insertSort(bucket);
                for (int j = 0; j < bucket.length; j++) {
                    array[currentDataIndex] = bucket[j];
                    currentDataIndex++;
                }
            }
        }
    }

    public static int getIntegerLength(int value) {
        return Integer.toString(value).length();
    }

    public static void main(String[] args) {
        int[] array = SortUtil.randomArray2(10);
        println(array);
        bucketSort(array);
        println(array);
    }

}

基数排序

  1. 以LSD为例,假设原来有一串数值如下所示:73, 22, 93, 43, 55, 14, 28, 65, 39, 81。首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中
  2. 接下来将这些桶子中的数值重新串接起来,成为以下的数列:81, 22, 73, 93, 43, 14, 55, 65, 28, 39。接着再进行一次分配,这次是根据十位数来分配
  3. 接下来将这些桶子中的数值重新串接起来,成为以下的数列:14, 22, 28, 39, 43, 55, 65, 73, 81, 93。这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止
package org.gallant.algorithm;

import static org.gallant.algorithm.SortUtil.println;

/**
 * @author 会灰翔的灰机
 * @date 2020/1/20
 */
public class RadixSort {

    public static void radixSort(int[] array) {
        int maxLen = 0;
        for (int i = 0; i < array.length; i++) {
            int currentValue = array[i];
            int len = Integer.toString(currentValue).length();
            if (len > maxLen) {
                maxLen = len;
            }
        }
        // 1. 从个位数至最高位,按每个位的数字进行分桶,逐个执行桶排序
        for (int i = 0; i < maxLen; i++) {
            Integer[][] buckets = new Integer[10][array.length];
            // 2. 分桶
            for (int j = 0; j < array.length; j++) {
                int currentValue = array[j];
                String currentValueStr = String.valueOf(currentValue);
                // 自右向左的游标
                int cursorIndex = (currentValueStr.length() - 1) - i;
                int index = cursorIndex >= 0 ? Character.getNumericValue(currentValueStr.charAt(cursorIndex)) : 0;
                Integer[] bucket = buckets[index];
                for (int k = 0; k < bucket.length; k++) {
                    if (bucket[k] == null) {
                        bucket[k] = currentValue;
                        break;
                    }
                }
            }
            int j = 0;
            // 2. 分桶后,按照桶顺序重组数组
            for (int i1 = 0; i1 < buckets.length; i1++) {
                Integer[] bucket = buckets[i1];
                System.out.print("当前桶 "+ i1 + " : ");
                for (Integer integer : bucket) {
                    if (integer != null) {
                        System.out.print(integer + ",");
                        array[j++] = integer;
                    }
                }
                System.out.println();
            }
            System.out.println("由低位至高位遍历分桶排序,当前位数:" + (i + 1) + ",重组后数组顺序");
            println(array);
        }
    }

    public static void main(String[] args) {
        int[] array = SortUtil.randomArray2(9);
        println(array);
        radixSort(array);
        println(array);
    }

}

堆排序

package org.gallant.algorithm;

import static org.gallant.algorithm.SortUtil.println;

/**
 * 参考:https://www.geeksforgeeks.org/heap-sort/
 * @author 会灰翔的灰机
 * @date 2020/1/21
 */
public class HeapSort {

    /**
     * 初始数组被看作一个完全二叉树
     * Input data: 4, 10, 3, 5, 1
     *          4(0)
     *         /   \
     *      10(1)   3(2)
     *     /   \
     *  5(3)    1(4)
     *
     * The numbers in bracket represent the indices in the array
     * representation of data.
     *
     * Applying heapify procedure to index 1:
     *          4(0)
     *         /   \
     *     10(1)    3(2)
     *     /   \
     * 5(3)    1(4)
     *
     * Applying heapify procedure to index 0:
     *         10(0)
     *         /  \
     *      5(1)  3(2)
     *     /   \
     *  4(3)    1(4)
     * The heapify procedure calls itself recursively to build heap
     *  in top down manner.
     */
    public static void heapSort(int[] array) {
        int heapSize = array.length;
        // 1. 构建最大堆。最大堆的每个非叶子节点都是左右子树的最大节点。即:构建之后0索引处为整棵树的最大值
        for (int i = heapSize / 2 - 1; i >= 0; i--) {
            heapify(array, heapSize, i);
        }
        for (int i = array.length - 1; i >= 0 ; i--) {
            // 2. 将最大值交换至最后,剩余[0, n - 2]恢复非最大堆状态。n - 1索引处为当前最大堆中的最大值
            swap(array, i, 0);
            // 3. 重复步骤1,2,直至整个堆有序
            heapify(array, i, 0);
        }
    }

    public static void heapify(int[] array, int heapSize, int largestNodeIndex) {
        // 初始化根节点
        int largest = largestNodeIndex;
        // 根节点左子节点索引
        int leftChild = 2 * largestNodeIndex + 1;
        // 根节点右子节点索引
        int rightChild = 2 * largestNodeIndex + 2;
        // 如果左子树大于根节点,更新根节点索引
        if (leftChild < heapSize && array[leftChild] > array[largest]) {
            largest = leftChild;
        }
        // 如果右子树大于根节点,更新根节点索引
        if (rightChild < heapSize && array[rightChild] > array[largest]) {
            largest = rightChild;
        }
        // 根节点索引发生变更,更新根节点
        if (largest != largestNodeIndex) {
            swap(array, largest, largestNodeIndex);
            // 左子树或右子树发生变更,递归更新发生变更的子树
            heapify(array, heapSize, largest);
        }
    }

    public static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    public static void main(String[] args) {
        int[] array = SortUtil.randomArray(9);
        println(array);
        heapSort(array);
        println(array);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值