常用排序算法总结(Java)
来源:互联网 发布:百度统计怎么查看数据 编辑:程序博客网 时间:2024/04/29 19:52
自己学习排序算法的练习总结
https://github.com/pengyuntao/Sort_Algorithms_Java
判断排序算法是否稳定:就是判断原本相等的两个数前后相对位置有没有变化,没有变化就是稳定,变化了就是不稳定。
冒泡排序
需要两两比较,大的数字逐渐移动到后边,很像水中的气泡冒出来,成为冒泡排序。
时间复杂度为O(n^2),稳定的排序算法
public class BubbleSort { //排序算法稳定 排序后与排序前两个相等的元素前后相对位置没有变化 private void swap(int[] array, int key1, int key2) { int temp = array[key1]; array[key1] = array[key2]; array[key2] = temp; } /** * 相邻两两比较,大数逐渐冒泡到最右边,内部循环的长度越来越小 * * @param array */ private void bubbleSort(int[] array) { for (int i = 0; i < array.length; i++) { boolean isSwap = false; for (int j = array.length - 2; j >= i; j--) { if (array[j] > array[j + 1]) { swap(array, j, j + 1); isSwap = true; } } if (!isSwap) { break; } } } @Test public void testCase1() { int[] arr = {85, 24, 11, 17, 63, 45, 17, 31, 96, 50}; bubbleSort(arr); System.out.println(Arrays.toString(arr)); }}
快速排序
主要是分治思想,对每个子数组进行快排,直到全排完为止。partition方法作用是把数据分成两部分,小的在左边,大的在右边。有两种写法:一种是两个指针从两端向中间扫描,另一种是两个指针同时从左向右扫描。最终结果是把比枢轴位置的数大的调整到数组右边,比枢轴位置的数小的数调整到数组左边。
时间复杂度为O(nlogn)是不稳定的排序
public class QuickSort { private void swap(int[] array, int key1, int key2) { int temp = array[key1]; array[key1] = array[key2]; array[key2] = temp; } private int partition1(int[] array, int low, int high) { // 利用Random随机获取low到high之间的一个值作枢轴索引,并将其与array[high]进行交换 int pivot = new Random().nextInt(high - low) + low; swap(array, pivot, high); // 单向扫描:right向右遍历array,当遇到小于pivot的元素,则与left当前指向的元素进行交换, // 否则直接跳过,一直到达array的最右边right为主动遍历,left为被动遍历 int left = low, right = low; while (right < high) { if (array[right] < array[high]) { // 如果array[r]是array中最大的元素,则right遇到的所有元素都要与left指向的元素进行交换 // 如果left与right相等,则交换是不必要的 if (left != right) { swap(array, left, right); } left++; right++; } else { // 如果array[r]是array中最小的元素,则left会一直停留在l处 right++; } } // 最终需要将pivot元素换回其排序最终位置,也就是left当前的位置 swap(array, left, high); return left; } private int partition2(int[] array, int low, int high) { int key = array[low]; while (low < high) { while (low < high && array[high] >= key) { high--; } swap(array, low, high); while (low < high && array[low] <= key) { low++; } swap(array, low, high); } return low; } private void quickSort1(int[] array, int low, int high) { if (low < high) { int pivot = partition1(array, low, high); quickSort1(array, low, pivot - 1); quickSort1(array, pivot + 1, high); } } private void quickSort2(int[] array, int low, int high) { if (low < high) { int pivot = partition2(array, low, high); quickSort2(array, low, pivot - 1); quickSort2(array, pivot + 1, high); } } @Test public void testCase1() { int[] arr = {85, 24, 11, 17, 63, 45, 17, 31, 96, 50}; quickSort1(arr, 0, arr.length - 1); System.out.println(Arrays.toString(arr)); } @Test public void testCase2() { int[] arr = {85, 24, 11, 17, 63, 45, 17, 31, 96, 50}; quickSort2(arr, 0, arr.length - 1); System.out.println(Arrays.toString(arr)); }}
堆排序
从小到大排列,使用大顶堆。依次取出大顶堆的顶部元素,对剩下的元素调整堆。重复上述过程。
堆排序时间复杂度为O(nlogn),是不稳定的排序算法
public class HeapSort { private void swap(int[] array, int key1, int key2) { int temp = array[key1]; array[key1] = array[key2]; array[key2] = temp; } //i为根节点 2*i+1为左孩子 2*i+2为右孩子 length/2-1为最后一个非叶子节点 /** * 堆排序 * * @param array */ private void heapSort(int[] array) { for (int i = array.length / 2 - 1; i >= 0; i--) { adjustHeap(array, i, array.length - 1); } for (int i = array.length - 1; i > 0; i--) { swap(array, 0, i); adjustHeap(array, 0, i - 1); } } /** * 调整堆 * * @param array 数组 * @param start 第一位索引 * @param end 最后一位索引 */ private void adjustHeap(int[] array, int start, int end) { int root = array[start]; int r = start; for (int i = start * 2 + 1; i < end; i = i * 2 + 1) { if (i < end && array[i] < array[i + 1]) { //选出两个孩子中大的一个 i++; } //因为是大顶堆,如果root比孩子大了那么就不用交换了 if (root > array[i]) { break; } //把大的孩子赋值给局部的根元素 array[r] = array[i]; r = i; } array[r] = root;//插入到正确的位置 } @Test public void testCase1() { int[] arr = {85, 24, 11, 17, 63, 45, 17, 31, 96, 50}; heapSort(arr); System.out.println(Arrays.toString(arr)); }}
插入排序
插入排序的思想类似于摸扑克牌,把摸的牌放入对应位置。默认第一个有序,依次把后边无序的向前边有序的元素中插入,使前边有序的序列向后扩展,直到所有的有序为止。
插入排序时间复杂度为O(n^2),是稳定的排序算法。
public class InsertSort { public void directInsertSort(int[] array) { for (int i = 1; i < array.length; i++) { int j = i; int temp = array[j]; while (j > 0 && temp < array[j - 1]) { array[j] = array[j - 1]; j--; } array[j] = temp; } } @Test public void testCase1() { int[] arr = {85, 24, 11, 17, 63, 45, 17, 31, 96, 50}; directInsertSort(arr); System.out.println(Arrays.toString(arr)); }}
希尔排序
希尔排序的思想是让数组基本逐渐有序,就是按照一定的步长对元素跳着进行插入排序,然后不断的缩小步长直到1为止。例如初始步长为2,对索引为1,3,5位置的元素进行插入排序,然后缩小步长为1,就是对1,2,3,4,5位置元素排序。由于数组逐渐基本有序,所以每次插入的次数会减少,从而提高了效率。注意每次步长序列的选择目前还是个难题,自己适情况而定,但是最后一次排序步长必须为1.
时间复杂度O(nlogn)~O(n^2),不稳定的排序算法。
public class ShellSort { public void shellSort(int[] array) { int inc = array.length; do { inc = inc / 3 + 1;//增量,最后一趟排序必须为1 for (int i = inc; i < array.length; i++) {//下边代码为对增量序列进行插入排序 int j = i; int temp = array[j]; while (j >= inc && array[j - inc] > temp) { array[j] = array[j - inc]; j = j - inc; } array[j] = temp; } } while (inc > 1); } @Test public void testCase1() { int[] arr = {0, 50, 10, 20, 30, 70, 40, 80, 60}; shellSort(arr); System.out.println(Arrays.toString(arr)); }}
选择排序
选择排序就是内部循环先找到最小的,然后做一次交换,减少了交换次数。
时间复杂度为O(n^2)
public class SelectionSort { private void swap(int[] array, int key1, int key2) { int temp = array[key1]; array[key1] = array[key2]; array[key2] = temp; } private void simpleSelectionSort(int[] array) { for (int i = 0; i < array.length; i++) { int min = i; for (int j = i; j < array.length; j++) { if (array[j] < array[min]) { min = j; } } if (min != i) { swap(array, min, i); } } } @Test public void testCase1() { int[] arr = {85, 24, 11, 17, 63, 45, 17, 31, 96, 50}; simpleSelectionSort(arr); System.out.println(Arrays.toString(arr)); }}
归并排序
归并其实就是先递归分成多部分,直到分成两两比较排序,然后在一点点合并排序。分治思想。
时间复杂度是O(nlogn),稳定的排序算法,缺点需要O(n)的辅助空间。
public class MergeSort { public void mergeSort(int[] array) { if (array == null) { return; } mergeSort(array, new int[array.length], 0, array.length - 1); } private void mergeSort(int[] array, int[] temp, int start, int end) { if (start < end) { int pivot = (start + end) / 2; mergeSort(array, temp, start, pivot); mergeSort(array, temp, pivot + 1, end); merge(array, temp, start, pivot, end); } } private void merge(int[] array, int[] temp, int start, int pivot, int end) { int i = start, j = pivot + 1, k = start; while (i <= pivot && j <= end) { if (array[i] <= array[j]) { temp[k++] = array[i++]; } else { temp[k++] = array[j++]; } } while (j <= end) { temp[k++] = array[j++]; } while (i <= pivot) { temp[k++] = array[i++]; } for (int n = start; n <= end; n++) { array[n] = temp[n]; } } @Test public void testCase1() { int[] arr = {50, 10, 20, 30, 70, 40, 80, 60}; mergeSort(arr); System.out.println(Arrays.toString(arr)); } @Test public void testCase2() { int[] arr = {85, 24, 11, 17, 63, 45, 17, 31, 96, 50}; mergeSort(arr); System.out.println(Arrays.toString(arr)); }}
桶排序
桶排序是直接利用一个函数把当前元素映射到指定的桶中,有种哈希的感觉。
基数排序
分别对数字的每一位进行排序
计数排序
准备带排列范围内的数量的桶,并按照范围内的数字编号,初始化为0,遍历待排序的数组,遇到一个数字,对应的桶中数字加1,然后按桶顺序及其内部统计的次数来输出排序数字。
2 0
- 常用排序算法总结(Java)
- 常用排序算法总结---Java实现
- 常用排序算法总结 JAVA代码
- Java常用排序算法冒泡排序与选择排序总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法 总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- CSAPP LAB4 perflab-handout性能优化 smooth负优化详解
- 解决Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’错误
- python处理文件tab替换成空格
- Docker学习系列(五):Dockerfile文件
- 第十二周项目 Time类中的运算符重载
- 常用排序算法总结(Java)
- 设计用户界面
- 树
- 希尔排序java版
- Precision和Recall
- Problem H: Eat Candy
- thinkphp RBAC权限节点递归
- NativeBayes Hadoop MapReduce
- java线程范围内的数据共享