• java实现各种排序


    /**
     * 冒泡排序
     */
    public class BubbleSort {
       /**
        * 冒泡排序,持续比较相邻元素,大的挪到后面,因此大的会逐步往后挪,故称之为冒泡。
        * 复杂度分析:平均情况与最坏情况均为 O(n^2), 使用了 temp 作为临时交换变量,空间复杂度为 O(1).
        */
        public static void main(String[] args) {
            int[] list = {27, 76, 47, 23, 7, 32, 19, 86};
            System.out.println("************冒泡排序************");
            System.out.println("排序前:");
            display(list);
            System.out.println("排序后:");
            bubbleSort(list);
            display(list);
        }
    
        /**
         * 遍历打印
         */
        public static void display(int[] list) {
            if (list != null && list.length > 0) {
                for (int num :
                        list) {
                    System.out.print(num + " ");
                }
                System.out.println("");
            }
        }
    
        /**
         * 冒泡排序算法
         */
        public static void bubbleSort(int[] list) {
           int len = list.length ;
            // 做多少轮排序(最多length-1轮)
            for (int i = 0; i < len - 1; i++) {
                // 每一轮比较多少个
                for (int j = 0; j < len - 1 - i; j++) {
                    if (list[j] > list[j + 1]) {
                        // 交换次序
                       int temp = list[j];
                        list[j] = list[j + 1];
                        list[j + 1] = temp;
                    }
                }
            }
        }
    }
    /**
     * 堆排序
     */
    public class HeapSort {
       /**
        * 堆排序的是集合了插入排序的单数组操作,又有归并排序的时间复杂度,完美的结合了2者的优点。
        * 参考:https://www.cnblogs.com/huenchao/p/5906193.html
        */
        public static void main(String[] args) {
           int[] list = {27, 76, 47, 23, 7, 32, 19, 86};
            System.out.println("************堆排序************");
            System.out.println("排序前:");
            display(list);
            System.out.println("排序后:");
            heapSort(list);
            display(list);
        }
    
        /**
         * 堆排序算法
         */
        public static void heapSort(int[] list) {
            // 将无序堆构造成一个大根堆,大根堆有length/2个父节点
            for (int i = list.length / 2 - 1; i >= 0; i--) {
                headAdjust(list, i, list.length);
            }
    
            // 逐步将每个最大值的根节点与末尾元素交换,并且再调整其为大根堆
            for (int i = list.length - 1; i > 0; i--) {
                // 将堆顶节点和当前未经排序的子序列的最后一个元素交换位置
                swap(list, 0, i);
                headAdjust(list, 0, i);
            }
        }
    
        /**
         * 构造大根堆
         */
        public static void headAdjust(int[] list, int parent, int length) {
            // 保存当前父节点
            int temp = list[parent];
    
            // 得到左孩子节点
            int leftChild = 2 * parent + 1;
    
            while (leftChild < length) {
                // 如果parent有右孩子,则要判断左孩子是否小于右孩子
                if (leftChild + 1 < length && list[leftChild] < list[leftChild + 1]) {
                    leftChild++;
                }
                // 父亲节点大于子节点,就不用做交换
                if (temp >= list[leftChild]) {
                    break;
                }
                // 将较大子节点的值赋给父亲节点
                list[parent] = list[leftChild];
                // 然后将子节点做为父亲节点
                parent = leftChild;
                // 找到该父亲节点较小的左孩子节点
                leftChild = 2 * parent + 1;
            }
            // 最后将temp值赋给较大的子节点,以形成两值交换
            list[parent] = temp;
        }
    
        /**
         * 交换数组中两个位置的元素
         */
        public static void swap(int[] list, int top, int last) {
            int temp = list[top];
            list[top] = list[last];
            list[last] = temp;
        }
    
        /**
         * 遍历打印
         */
        public static void display(int[] list) {
            if (list != null && list.length > 0) {
                for (int num :list) {
                    System.out.print(num + " ");
                }
                System.out.println("");
            }
        }
    }
    
    /**
     * 直接插入排序
     */
    public class InsertSort {
       /**
        * 直接插入排序是一种最简单的排序方法,它的基本操作是将一个记录插入到已排好的有序的表中,从而得到一个新的、记录数增1的有序表。
             * 当前元素的前面元素均为有序,要插入时,从当前元素的左边开始往前找(从后往前找),比当前元素大的元素均往右移一个位置,最后把当前元素放在它应该呆的位置就行了。
         * 参考:https://www.cnblogs.com/mengdd/archive/2012/11/24/2786490.html
        */
        public static void main(String[] args) {
           int[] list = {27, 76, 47, 23, 7, 32, 19, 86};
            System.out.println("************直接插入排序************");
            System.out.println("排序前:");
            display(list);
            System.out.println("排序后:");
            insertSort(list);
            display(list);
        }
    
        /**
         * 直接插入排序算法
         */
        public static void insertSort(int[] list) {
           int len = list.length ;
            // 从无序序列中取出第一个元素 (注意无序序列是从第二个元素开始的)
            for (int i = 1; i < len; i++) {
                int temp = list[i];
                int j;
                // 遍历有序序列
                // 如果有序序列中的元素比临时元素大,则将有序序列中比临时元素大的元素依次后移
                for (j = i - 1; j >= 0 && list[j] > temp; j--) {
                    list[j + 1] = list[j];
                }
                // 将临时元素插入到腾出的位置中
                list[j + 1] = temp;
            }
        }
    
        /**
         * 遍历打印
         */
        public static void display(int[] list) {
            if (list != null && list.length > 0) {
                for (int num :list) {
                    System.out.print(num + " ");
                }
                System.out.println("");
            }
        }
    }
    /**
     * 归并排序
     */
    public class MergeSort {
       /**
        * 归并排序(Merge Sort)与快速排序思想类似:将待排序数据分成两部分,继续将两个子部分进行递归的归并排序;然后将已经有序的两个子部分进行合并,最终完成排序。
        * 其时间复杂度与快速排序均为O(nlogn),但是归并排序除了递归调用间接使用了辅助空间栈,还需要额外的O(n)空间进行临时存储。从此角度归并排序略逊于快速排序,但是归并排序是一种稳定的排序算法,快速排序则不然。
         * 所谓稳定排序,表示对于具有相同值的多个元素,其间的先后顺序保持不变。对于基本数据类型而言,一个排序算法是否稳定,影响很小,但是对于结构体数组,稳定排序就十分重要。例如对于student结构体按照关键字score进行非降序排序:
        */
        public static void main(String[] args) {
            int[] list = {50, 10, 90, 30, 70};
            System.out.println("************归并排序************");
            System.out.println("排序前:");
            display(list);
            System.out.println("排序后:");
            mergeSort(list, new int[list.length], 0, list.length - 1);
            display(list);
        }
    
        /**
         * 归并排序算法
         * @param list     待排序的列表
         * @param tempList 临时列表
         * @param head     列表开始位置
         * @param rear     列表结束位置
         */
        public static void mergeSort(int[] list, int[] tempList, int head, int rear) {
            if (head < rear) {
                // 取分割位置
                int middle = (head + rear) / 2;
                // 递归划分列表的左序列
                mergeSort(list, tempList, head, middle);
                // 递归划分列表的右序列
                mergeSort(list, tempList, middle + 1, rear);
                // 列表的合并操作
                merge(list, tempList, head, middle + 1, rear);
            }
        }
    
        /**
         * 合并操作(列表的两两合并)
         * @param list
         * @param tempList
         * @param head
         * @param middle
         * @param rear
         */
        public static void merge(int[] list, int[] tempList, int head, int middle, int rear) {
            // 左指针尾
            int headEnd = middle - 1;
            // 右指针头
            int rearStart = middle;
            // 临时列表的下标
            int tempIndex = head;
            // 列表合并后的长度
            int tempLength = rear - head + 1;
    
            // 先循环两个区间段都没有结束的情况
            while ((headEnd >= head) && (rearStart <= rear)) {
                // 如果发现右序列大,则将此数放入临时列表
                if (list[head] < list[rearStart]) {
                    tempList[tempIndex++] = list[head++];
                } else {
                    tempList[tempIndex++] = list[rearStart++];
                }
            }
    
            // 判断左序列是否结束
            while (head <= headEnd) {
                tempList[tempIndex++] = list[head++];
            }
    
            // 判断右序列是否结束
            while (rearStart <= rear) {
                tempList[tempIndex++] = list[rearStart++];
            }
    
            // 交换数据
            for (int i = 0; i < tempLength; i++) {
                list[rear] = tempList[rear];
                rear--;
            }
        }
    
        /**
         * 遍历打印
         */
        public static void display(int[] list) {
            if (list != null && list.length > 0) {
                for (int num :list) {
                    System.out.print(num + " ");
                }
                System.out.println("");
            }
        }
    }
    
    /**
     * 快速排序
     */
    public class QuickSort {
       /**
        * 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
        */
        public static void main(String[] args) {
            int[] list = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8};
            System.out.println("************快速排序************");
            System.out.println("排序前:");
            display(list);
            System.out.println("排序后:");
            quickSort(list, 0, list.length - 1);
            display(list);
        }
    
        /**
         * 快速排序算法
         */
        public static void quickSort(int[] list, int left, int right) {
            if (left < right) {
                // 分割数组,找到分割点
                int point = partition(list, left, right);
    
                // 递归调用,对左子数组进行快速排序
                quickSort(list, left, point - 1);
                // 递归调用,对右子数组进行快速排序
                quickSort(list, point + 1, right);
            }
        }
    
        /**
         * 分割数组,找到分割点
         */
        public static int partition(int[] list, int left, int right) {
            // 用数组的第一个元素作为基准数
            int first = list[left];
            while (left < right) {
                while (left < right && list[right] >= first) {
                    right--;
                }
                // 交换
                swap(list, left, right);
    
                while (left < right && list[left] <= first) {
                    left++;
                }
                // 交换
                swap(list, left, right);
            }
            // 返回分割点所在的位置
            return left;
        }
    
        /**
         * 交换数组中两个位置的元素
         */
        public static void swap(int[] list, int left, int right) {
            int temp;
            if (list != null && list.length > 0) {
                temp = list[left];
                list[left] = list[right];
                list[right] = temp;
            }
        }
    
        /**
         * 遍历打印
         */
        public static void display(int[] list) {
            if (list != null && list.length > 0) {
                for (int num :list) {
                    System.out.print(num + " ");
                }
                System.out.println("");
            }
        }
    }
    /**
     * 直接选择排序
     */
    public class SelectionSort {
       /**
        * 所谓选择排序,就是每次找到未排序中最小的(最大的也行)元素的位置,找到后与该位置与未排序序列的第一个元素交换值,直到该序列成为有序序列。
        * 初始状态整个序列为无序序列,每次交换都使有序序列的长度加一,无序序列的起始位置后移一位。选择排序的平均时间复杂度为O(n^2),且选择排序相对不稳定。
        */
        public static void main(String[] args) {
           int[] list = {27, 76, 47, 23, 7, 32, 19, 86};
            System.out.println("************直接选择排序************");
            System.out.println("排序前:");
            display(list);
            System.out.println("排序后:");
            selectionSort(list);
            display(list);
        }
    
        /**
         * 直接选择排序算法
         */
        public static void selectionSort(int[] list) {
           int len = list.length ;
            // 要遍历的次数(length-1次)
            for (int i = 0; i < len - 1; i++) {
                // 将当前下标定义为最小值下标
                int min = i;
    
                // 遍历min后面的数据
                for (int j = i + 1; j <= len - 1; j++) {
                    // 如果有小于当前最小值的元素,将它的下标赋值给min
                    if (list[j] < list[min]) {
                        min = j;
                    }
                }
                // 如果min不等于i,说明找到真正的最小值
                if (min != i) {
                    swap(list, min, i);
                }
            }
        }
    
        /**
         * 交换数组中两个位置的元素
         */
        public static void swap(int[] list, int min, int i) {
            int temp = list[min];
            list[min] = list[i];
            list[i] = temp;
        }
    
        /**
         * 遍历打印
         */
        public static void display(int[] list) {
            if (list != null && list.length > 0) {
                for (int num :list) {
                    System.out.print(num + " ");
                }
                System.out.println("");
            }
        }
    }
    
    /**
     * 希尔排序
     */
    public class ShellSort {
       /**
        * Shellsort是最古老的排序算法之一,该算法以其发明者Donald L. Shell的名字命名(1959)。
        * 在ShellSort排序算法之前的算法时间复杂度基本都是O(n2)O(n2),该算法是突破这个时间复杂度的第一批算法之一。
        * 另外 Shellsort 是快速、易于理解和易于实现的。 然而,其复杂度分析有点复杂。
        */
        public static void main(String[] args) {
           int[] list = {27, 76, 47, 23, 7, 32, 19, 86};
            System.out.println("************希尔排序************");
            System.out.println("排序前:");
            display(list);
            System.out.println("");
    
            System.out.println("排序后:");
            shellSort(list);
            display(list);
        }
    
        /**
         * 希尔排序算法
         */
        public static void shellSort(int[] list) {
           int len = list.length ;
            // 取增量
            int gap = len / 2;
    
            while (gap >= 1) {
                // 无序序列
                for (int i = gap; i < len; i++) {
                    int temp = list[i];
                    int j;
    
                    // 有序序列
                    for (j = i - gap; j >= 0 && list[j] > temp; j = j - gap) {
                        list[j + gap] = list[j];
                    }
                    list[j + gap] = temp;
                }
    
                // 缩小增量
                gap = gap / 2;
            }
        }
    
        /**
         * 遍历打印
         */
        public static void display(int[] list) {
            if (list != null && list.length > 0) {
                for (int num :list) {
                    System.out.print(num + " ");
                }
                System.out.println("");
            }
        }
    }
    
    /**
     * 
     * 百亿数据中取中位数
     * 场景:股市上一个股票的价格从开市开始是不停的变化的,需要开发一个系统,给定一个股票,它能实时显示从开市到当前时间的这个股票的价格的中位数(中值)。
     * 创建者 柒
     * 创建时间    2018年12月21日
     */
    public class FindMedian {
       //maxHeap保存较小的半边数据,minHeap保存较大的半边数据。
        private static PriorityQueue<Integer> maxHeap, minHeap;
    
        public static void main(String[] args) {
    
            Comparator<Integer> revCmp = new Comparator<Integer>() {
                @Override
                public int compare(Integer left, Integer right) {
                    return right.compareTo(left);
                }
            };
    
            maxHeap = new PriorityQueue<Integer>(100, revCmp);
            minHeap = new PriorityQueue<Integer>(100);
            Random ra =new Random();
            for(int i=0;i<=100;i++){
               int number = ra.nextInt(200);
               addNumber(number);
            }
            System.out.println(minHeap);
            System.out.println(maxHeap);
            System.out.println(getMedian());
        }
    
        /*
         * offer 新增元素
         * peek 头部查询元素
         * poll 队列中删除从头部
         * 1)比较两个堆的大小,第一次肯定相同,此时两个堆都没有数据,把第一个数据放入大堆
         * 2)比较两个堆的大小,第二次肯定不同,如果value值小于大堆头部的值,小堆加入大堆头部元素,大堆加入当前值
         * 注意:
         * 并不是线程安全的,多线程访问操作会有并发问题
         */
        public static void addNumber(int value) {
            if (maxHeap.size() == minHeap.size()) {
                if (minHeap.peek() != null && value > minHeap.peek()) {
                    maxHeap.offer(minHeap.poll());
                    minHeap.offer(value);
                } else {
                    maxHeap.offer(value);
                }
            } else {
                if (value < maxHeap.peek()) {
                    minHeap.offer(maxHeap.poll());
                    maxHeap.offer(value);
                } else {
                    minHeap.offer(value);
                }
            }
        }
    
        /*
         * If maxHeap and minHeap are of different sizes, 
         * then maxHeap must have one extra element.
         */
        public static double getMedian() {
            if (maxHeap.isEmpty()) {
                return -1; 
            }
            
            if (maxHeap.size() == minHeap.size()) {
                return (double)(minHeap.peek() + maxHeap.peek())/2;
            } else {
                return maxHeap.peek();
            }
        }
    }
    

  • 相关阅读:
    Ubuntu记录
    VMware下的ubuntu虚拟机,实现虚拟机与本地硬盘间的文件互传
    pat basic 1084 外观数列
    SpringBoot集成MyBatis-Plus实现增删改查
    VUE面试题
    Three.js + Tensorflow.js 构建实时人脸点云
    考研英语语法(十)
    Flink学习之旅:(一)Flink部署安装
    DMBOK知识梳理for CDGA/CDGP——第一章数据管理(附常考知识点)
    WebSocket、event-source、AJAX轮询 等实现保持前后端实时通信的方式
  • 原文地址:https://blog.csdn.net/qq_42093488/article/details/125481029