各种常用排序算法比较 | ||||||
类别 | 排序方法 | 时间复杂度 | 空间复杂度 | 稳定性 | ||
平均情况 | 最好情况 | 最坏情况 | 辅助内存 | |||
插入排序 | 直接插入 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
Shell排序 | O(n^1.3) | O(n) | O(n^2) | O(1) | 不稳定 | |
选择排序 | 直接选择 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
堆排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(1) | 不稳定 | |
交换排序 | 冒泡排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
快速排序 | O(nlog2n) | O(nlog2n) | O(n^2) | O(nlog2n) | 不稳定 | |
归并排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(1) | 稳定 | |
基数排序 | O(d(r+n)) | O(d(n+rd)) | O(d(r+n)) | O(rd+n) | 稳定 |
冒泡排序
思路
遍历整个数组,分别比较相邻的两个元素,把如果前一个大于后一个元素,则交换这两个元素。第一次遍历把最大的元素交换到数组的末尾。
以后按照上述的步骤,每次把剩余最大的元素交换到剩余的末尾。
代码
public static void maopaoSort(int[] datas){
int length = datas.length;
int temp = 0;
for(int i = length - 1;i >= 1;i--){
for(int j = 0;j < i;j++){
if(datas[j] > datas[j + 1]){
temp = datas[j];
datas[j] = datas[j + 1];
datas[j + 1] = temp;
}
}
}
}
选择排序
思路
给每个位置选择元素
对于每个位置,遍历其以及后面所有的元素,找到最小元素的位置,然后把该位置与最小元素位置的元素交换。
代码
public static void selectSort(int[] datas){
int length = datas.length;
int temp = 0;
for(int i = 0;i < length - 1;i++){
int min = i;
for(int j = i + 1;j < length;j++){
if(datas[j] < datas[min])min = j;
}
if(min != i){
temp = datas[i];
datas[i] = datas[min];
datas[min] = temp;
}
}
}
插入排序
思路
给元素选择合适位置
从第一个元素开始
从它的位置开始分别和前面的元素比较,如果该元素小于前面的元素,就和前面的元素交换。
代码
public static void insertSort(int[] datas){
int length = datas.length;
int temp = 0;
for(int i = 1;i < length;i++){
for(int j = i;j >0;j--){
if(datas[j] < datas[j - 1]){
temp = datas[j];
datas[j] = datas[j - 1];
datas[j - 1] = temp;
}else {
break;
}
}
}
}
快速排序
思路
每次选择一个基准元素,找到该基准元素应有的位置:即该元素前面的元素都小于等于它,后面的元素都大于等于它。
然后分别递归的对该元素前半部分和后半部分重复该步骤。
代码
public static void quickSort(int[] datas,int left,int right){
if(left > right)return;
int index = partion(datas,left,right);
quickSort(datas,left,index - 1);
quickSort(datas,index + 1,right);
}
public static int partion(int[] datas,int left,int right){
while(left < right) {
while (datas[right] >= datas[left] && left < right) right--;
int temp = datas[right];
datas[right] = datas[left];
datas[left] = temp;
while (datas[right] >= datas[left] && left < right) left++;
temp = datas[right];
datas[right] = datas[left];
datas[left] = temp;
}
return left;
}
归并排序
思路
采用分治的思想
把整个数组分成只有1个或者2个元素的数组,对子数组排序,然后把排好序的子数组合并。整个数组即有序。
代码
public static void guibinSort(int[] datas,int l,int r,int[] result){
if(r - l <= 1)return;
int m = (l + r) / 2;
guibinSort(datas,l,m,result);
guibinSort(datas,m+1,r,result);
guibin(datas,l,m,r,result);
}
public static void guibin(int[] datas,int l,int m,int r,int [] result){
int s1 = l,s2 = m + 1,s3 = l;
while (s1 <= m && s2 <= r){
if(datas[s1] <= datas[s2]){
result[s3] = datas[s1];
s3++;
s1++;
}else {
result[s3] = datas[s2];
s3++;
s2++;
}
}
while(s1 <= m){
result[s3] = datas[s1];
s3++;
s1++;
}
while(s2 <= r){
result[s3] = datas[s2];
s3++;
s2++;
}
for(int i = l;i <= r;i++){
datas[i] = result[i];
}
}
堆排序
思路
最大堆:是一个完全二叉树,根节点大于等于左右子节点的值。
完全二叉树的性质:叶子节点的个数总是等于非叶子节点的个数或者叶子节点个数比非叶子节点个数多一。
先把一个数组根据下标映射成完全二叉树 i节点的左右子节点的位置分别为2*k+1和2*k+2
把数组构造成最大堆
把根节点元素和数组末尾元素交换,属于的数组调整成最大堆,再交换根节点和末尾节点的元素
代码
public static void maxHeapSort(int[] datas){
int length = datas.length;
//构造最大堆
createMaxHeap(datas);
//交换元素并且重新构造最大堆
for(int j = length - 1;j > 0;j--){
swap(datas,0,j);
adjustHeap(datas,0,j - 1);
}
}
public static void createMaxHeap(int[] datas){
int length = datas.length;
int noLeaf = length / 2 - 1;
int max = 0;
for(int i = noLeaf;i >= 0;i--){
adjustHeap(datas,i,length - 1);
}
}
public static void swap(int[] datas,int i,int j){
int temp = datas[i];
datas[i] = datas[j];
datas[j] = temp;
}
public static void adjustHeap(int[] datas,int i,int end){
int temp = datas[i];
for(int k = 2 * i + 1;k <= end;k = 2 * k + 1){
if(k + 1 <= end && datas[k + 1] > datas[k])k++;
if(datas[i] < datas[k]){
swap(datas,i,k);
i = k;
}else {
break;
}
}
}
希尔排序
思路
希尔排序是改变步长的插入排序
每次插入排序的时候通过不同步长将数组分成几个子序列,对这几个子序列插入排序。
最后再对整个数组插入排序,也就是步长为一
因为插入排序在数组基本有序时效率最高
代码
public static void shellSort(int[] datas){
int length = datas.length;
for(int gap = length / 2;gap > 0;gap /= 2){
for(int i = gap;i < length;i++){
insertI(datas,gap,i);
}
}
}
public static void insertI(int[] datas,int gap,int i){
int inserted = datas[i];
int j = 0;
for(j = i - gap;j >= 0 && inserted < datas[j];j -= gap){
datas[j + gap] = datas[j];
}
datas[j + gap] = inserted;
}
基数排序
思路
基数排序根据所有元素的每一位的个数把所有元素放在一个“桶中”
再把所有的“桶”中的元素按照“桶”的大小串起来。
代码
public static void jishuSort(int[] datas,int d){
int m = 1,k = 0,n = 1;
int[][] temp = new int[10][datas.length];
int[] order = new int[10];
for(int i = 0;i < order.length;i++)order[i] = 0;
while(n <= d){
for(int i = 0;i < datas.length;i++){
int lsd = (datas[i] / m) % 10;
temp[lsd][order[lsd]] = datas[i];
order[lsd]++;
}
for(int i = 0;i < 10;i++){
if(order[i] != 0){
for(int j = 0;j < order[i];j++){
datas[k++] = temp[i][j];
}
}
order[i] = 0;
}
m *= 10;
k = 0;
n++;
}
}