/** * 冒泡排序 */ 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(); } } }