常见八大排序
创始人
2024-06-03 16:18:16
0

目录

一、插入排序

二、希尔排序

三、选择排序

四、堆排序

五、冒泡排序

六、快速排序

七、归并排序

八、计数排序


一、插入排序

排序过程:

从第 j 个数字开始,往前面寻找比 arr[j] 小的数,如果找到比 arr[j] 小的数,假设下标为 i,然后交换 arr[i] 和 arr[j] 即可。

时间复杂度:最好情况(正序)下是 O(N),最坏情况(逆序)下是O(N^2)

空间复杂度:O(1)

稳定性:稳定

private static void InsertSort(int[] arr) {for (int i = 1; i < arr.length; i++) {int tmp = arr[i];int j = i;for (; j > 0; j--) {if (tmp < arr[j-1]) {arr[j] = arr[j-1];}else {break;}}arr[j] = tmp;}}

二、希尔排序

排序过程:

在插入排序的基础之上分组进行排序,设置一个间隔 gap,然后按照 gap 进行分组,在分好的每个小组进行插入排序。

时间复杂度:O(N^1.3~N^1.5)

空间复杂度:O(1)

稳定性:不稳定

private static void shellSort(int[] arr) {int gap = arr.length;while (gap > 1) {shell(arr,gap);// gap 每次都除以2,可以减少排序的次数// 如果除数太大,和直接使用插入排序效果差不多// 如果一次次的 -1或者 -2,就需要多次分组排序,这也会降低效率gap /= 2;}shell(arr,1);
}
​
private static void shell(int[] arr, int gap) {for(int i = gap; i < arr.length; i++) {int tmp = arr[i];int j = i-gap;for(; j >= 0; j -= gap) {if (tmp < arr[j]) {arr[j+gap] = arr[j];}else {break;}}arr[j+gap] = tmp;}
}

三、选择排序

直接选择排序过程:

从下标为 i 处开始,往后遍历,找到值最小的数字的位置 minIndex,并且交换 arr[i] 和 arr[minIndex]。

时间复杂度:O(N*logN)--- 直接选择排序对数据不敏感,无论有序还是无序,时间复杂度都是O(n^2)

空间复杂度:O(1)

稳定性:不稳定

private static void selectSort(int[] arr) {for(int i = 0; i < arr.length; i++) {int minIndex = i;for (int j = i; j < arr.length; j++) {minIndex = arr[minIndex] > arr[j] ? j : minIndex;}swap(arr,i,minIndex);}
}private static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;
}

双指针选择排序过程:

同时遍历出最小值和最大值,然后在左右两侧进行交换。

private static void selectSort2(int[] arr) {int left = 0;int right = arr.length-1;while (left < right) {int minIndex = left;int maxIndex = left;for(int j = left+1; j <= right; j++) {minIndex = arr[minIndex] > arr[j] ? j : minIndex;maxIndex = arr[maxIndex] < arr[j] ? j : maxIndex;}swap(arr,left,minIndex);// 修正 max 下标if (left == maxIndex) {maxIndex = minIndex;}swap(arr,right,maxIndex);left++;right--;}
}

四、堆排序

堆排序过程:

先创建一个大根堆,然后再从最后一个叶子结点开始往前调整。调整方式如图所示

时间复杂度:O(N*logN)

空间复杂度:O(1)

稳定性:不稳定

private static void heapSort(int[] arr) {// 建立大根堆createBigHeap(arr);// 调整的节点下标int end = arr.length-1;while(end > 0) {swap(arr,0,end);shidtDown(arr,0,end);end--}
}
private static void createBigHeap(int[] arr) {for (int parent = (arr.length-1-1)/2; parent >= 0; parent--) {//向下调整shiftDown(arr,parent,arr.length);}
}private static void shiftDown(int[] arr, int parent, int length) {// 判断左孩子int child = parent*2+1;while(child < length) {if (child + 1 < length && arr[child+1] > arr[child]) {child++;}if(arr[child] > arr[parent]) {swap(arr,child,parent);parent = child;child = parent*2+1;}else {break;}}
}
private static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;
}

五、冒泡排序

排序过程:

从 i 开始遍历,若 arr[i+1] > arr[i],则arr[i+1] 和 arr[i] 进行交换即可,交换一轮之后,最大值就会跑到最后一个位置。

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:稳定

private static void bubbleSort(int[] arr) {for (int i = 0; i < arr.length-1; i++) {// 用于优化排序boolean flg = false;for (int j = 0; j < arr.length-i-1; j++) {if (arr[j] > arr[j+1]) {swap(arr,j,j+1);}else {// 如果遍历一轮并没有任何交换,说明不存 arr[i+1] > arr[i]的情况flg = !flg;}}// flg == true 说明数组已经有序if (flg) {break;}}
}
private static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;
}

六、快速排序

1.Hoare法

时间复杂度:O(N*logN)——每次都是均分待排列序列,O(N^2)——数据有序或者逆序

空间复杂度:最好情况——O(logN),最坏情况O(N),当N越大的时候,递归的就越深

稳定性:不稳定

private static void quickSort(int[] arr) {quick(arr,0,arr.length-1);
}private static void quick(int[] arr, int left, int right) {if (left >= right) {return;}int pivot = partitionHoare(arr,left,right);quick(arr,left,pivot-1);quick(arr,pivot+1,right);
}
private static int partitionHoare(int[] arr, int left, int right) {// 事先存储好 left 和 right 下标int i = left;int j = right;int pivot = arr[left];while (i < j) {// 一定要先走右边,不然可能会把大于 pivot 的值传到左边while (i < j && arr[j] >= pivot) {j--;}while (i < j && arr[i] <= pivot) {i++;}swap(arr,i,j);}swap(arr,i,left);return i;
}
private static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;
}

2.挖坑法

private static void quickSort(int[] arr) {quickHole(arr,0,arr.length-1);
}private static void quickHole(int[] arr, int left, int right) {if (left >= right) {return;}int pivot = partitionHole(arr,left,right);quickHole(arr,left,pivot-1);quickHole(arr,pivot+1,right);
}
private static int partitionHole(int[] arr, int left, int right) {int key = arr[left];while (left < right) {while (left < right && arr[right] >= key) {right--;}arr[left] = arr[right];while (left < right && arr[left] <= key) {left++;}arr[right] = arr[left];}arr[left] = key;return left;
}
private static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;
}

3.非递归实现快速排序

private static void quickSort(int[] arr) {Stack stack = new Stack<>();int left = 0;int right = arr.length-1;int pivot = partitionHole(arr,left,right);if (pivot > left+1) {stack.push(left);stack.push(pivot-1);}if (pivot < right-1) {stack.push(pivot+1);stack.push(right);}while (!stack.isEmpty()) {right = stack.pop();left = stack.pop();pivot = partitionHole(arr,left,right);if (pivot > left+1) {stack.push(left);stack.push(pivot-1);}if (pivot < right-1) {stack.push(pivot+1);stack.push(right);}}
}
private static int partitionHole(int[] arr, int left, int right) {int key = arr[left];while (left < right) {while (left < right && arr[right] >= key) {right--;}arr[left] = arr[right];while (left < right && arr[left] <= key) {left++;}arr[right] = arr[left];}arr[left] = key;return left;
}

七、归并排序

排序过程:先将原数组分成最小单元,然后再将这些最小的单元一个个有序的合并起来,如下图所示。

时间复杂度:O(N*logN)

空间复杂度:O(N)

稳定性:稳定

private static void mergeSort(int[] arr) {mergeSortFunc(arr,0,arr.length-1);
}private static void mergeSortFunc(int[] arr, int left, int right) {// 结束条件if (left >= right) {return;}int mid = (left+right)/2;mergeSortFunc(arr,left,mid);mergeSortFunc(arr,mid+1,right);// 合并merge(arr,left,right,mid);
}
private static void merge(int[] arr, int start, int end, int midIndex) {int s1 = start;// 第一个归并段的起点int s2 = midIndex+1;// 第二个归并段的起点int[] tmp = new int[end-start+1];int k = 0;while (s1 <= midIndex && s2 <= end) {if (arr[s1] <= arr[s2]) {tmp[k++] = arr[s1++];}else {tmp[k++] = arr[s2++];}}// 当一个归并段中没有数据之后while (s1 <= midIndex) {tmp[k++] = arr[s1++];}while (s2 <= end) {tmp[k++] = arr[s2++];}// 将 tmp 中的数据拷贝回原数组for (int i = 0; i < k; i++) {arr[i+start] = tmp[i];}
}

非递归实现归并排序

private static void mergeSort(int[] arr) {int gap = 1;while (gap < arr.length) {for (int i = 0; i < arr.length; i += gap*2) {int s1 = i;int e1 = s1+gap-1;if (e1 >= arr.length) {e1 = arr.length-1;}int s2 = e1+1;if (s2 >= arr.length) {s2 = arr.length-1;}int e2 = s2+gap-1;if (e2 >= arr.length) {e2 = arr.length-1;}merge(arr,s1,e2,e1);}gap *= 2;}}
private static void merge(int[] arr, int start, int end, int midIndex) {int s1 = start;// 第一个归并段的起点int s2 = midIndex+1;// 第二个归并段的起点int[] tmp = new int[end-start+1];int k = 0;while (s1 <= midIndex && s2 <= end) {if (arr[s1] <= arr[s2]) {tmp[k++] = arr[s1++];}else {tmp[k++] = arr[s2++];}}// 当一个归并段中没有数据之后while (s1 <= midIndex) {tmp[k++] = arr[s1++];}while (s2 <= end) {tmp[k++] = arr[s2++];}// 将 tmp 中的数据拷贝回原数组for (int i = 0; i < k; i++) {arr[i+start] = tmp[i];}
}

八、计数排序

排序过程:记录每个数据 val 出现的次数和该数字的大小,数字每出现一次 count[val] 就加 1,然后遍历 count,将记下的数据写回原数组中。

时间复杂度:O(N+范围)

空间复杂度:O(范围)

稳定性:无法判定

public static void countSort(int[] array) {int maxVal = array[0];int minVal = array[0];
​for (int i = 0; i < array.length; i++) {if(array[i] < minVal) {minVal = array[i];}if(array[i] > maxVal) {maxVal = array[i];}}//就能确定当前数组的最大值 和 最小值int len = maxVal - minVal + 1;int[] count = new int[len];//开始遍历array数组 进行计数for (int i = 0; i < array.length; i++) {int val = array[i];count[val-minVal]++;
​}
​int index = 0;//array数组的下标for (int i = 0; i < count.length; i++) {//确保 当前count数组 可以检查完while (count[i] != 0) {array[index] = i+minVal;index++;count[i]--;}}
}

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...