排序算法 | 平均时间复杂度 | 最好时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 算法分类 | 稳定性 |
---|---|---|---|---|---|---|
冒泡排序 | O(n^2) | O(n) | O(n^2) | O(1) | 比较类 | 稳定 |
插入排序 | O(n^2) | O(n) | O(n^2) | O(1) | 比较类 | 稳定 |
归并排序 | O(nlgn) | O(nlgn) | O(nlgn) | O(n) | 比较类 | 稳定 |
快速排序 | O(nlgn) | O(nlgn) | O(n^2) | O(n) | 比较类 | 不稳定 |
希尔排序 | O(n^1.5) | O(n) | O(n^2) | O(1) | 比较类 | 不稳定 |
选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 比较类 | 不稳定 |
堆排序 | O(nlgn) | O(nlgn) | O(nlgn) | O(1) | 比较类 | 不稳定 |
计数排序 | O(n+k) | O(n+k) | O(n+k) | O(n+k) | 非比较 | 稳定 |
桶排序 | O(n+k) | O(n) | O(n^2) | O(n+k) | 非比较 | 稳定 |
基数排序 | O(n*k) | O(n*k) | O(n*k) | O(n+k) | 非比较 | 稳定 |
1.冒泡排序
规则:将第一个元素与第二个元素进行比较 ,如果第一个比第二个大则交换位置。继续第二个与第三个比较与之前一样…
第一趟循环确定最后一个位置,第二趟循环确定倒二的位置…
代码示例(JAVA):
for (int i = 0; i < x.length; i++) {//循环次数
for (int j = 0; j < x.length-i-1; j++) {//每次交换的次数
if (x[j]>x[j+1]){
int tem = x[j];
x[j] = x[j+1];
x[j+1] = tem;
}
}
}
2.插入排序
规则:类似于摸牌一样,每次讲新牌插入到对应的位置,直到最后一张
代码示例(JAVA)
for (int i = 1; i < x.length; i++) {
int tem = x[i];//摸起的新牌
int j = i-1;
while (j>=0 && x[j]>tem){//如果前面的牌比较大则将位置后移一位 腾出前面的位置
x[j+1] = x[j];
j--;
}
x[j+1] = tem;//将牌放入位置
}
3.归并排序
规则:类似于化整为零,将数组对半拆分,拆分到只剩一个就是有序 然后在组合起来
public void sort(int[] x){
sort(x,0,x.length-1);
}
public void sort(int[] x,int start, int end){
if (start<end){
int mid = (start+end)/2;
sort(x,start,mid);//将数组继续拆分
sort(x,mid+1,end);//将数组继续拆分
merge(x,start,mid+1,end);
}
}
public void merge(int[] x,int start, int mid, int end){//合并
int[] s2 = new int[end-start+1];
int t = mid;
int i = start;
int index = 0;
while (i<mid && t<=end){
if (x[i]<=x[t]){
s2[index++] = x[i];
i++;
}else {
s2[index++] = x[t];
t++;
}
}
while (i<mid)s2[index++] = x[i++];
while (t<=end)s2[index++] = x[t++];
for (int l = 0; l < s2.length; l++) {
x[start+l] = s2[l];
}
}
4.快速排序
规则:选定一个锚点将数组中的数值跟锚点对比左右分组,小的分一组,大的分一组,分组完继续讲左右两堆分组,直至组中只有一个数则为有序
public void sort(int[] x){
sort(x,0,x.length-1);
}
public void sort(int[] x, int q, int r){
if (q<r){
int index = partition(x,q,r);
sort(x,q,index-1);//左边堆继续分组
sort(x,index+1,r);//右边堆继续分组
}
}
public int partition(int[] x, int q, int r){//将数组按照锚点左右分组
int tem = x[r];
int index = q-1;
for (int i = q; i < r; i++) {
if (tem>=x[i]){
index++;
if (i!=index){
int t = x[i];
x[i] = x[index];
x[index] = t;
}
}
}
x[r] = x[index+1];
x[index+1] = tem;
return index+1;
}
5.希尔排序
规则:插入排序的一种,先让数组中任意间隔为 h 的元素有序,刚开始 h 的大小可以是 h = n / 2,接着让 h = n / 4,让 h 一直缩小,当 h = 1 时,也就是此时数组中任意间隔为1的元素有序,此时的数组就是有序的了
public void sort(int[] x){
int h = x.length/2;
if (h<2) return;
for (int i = h; i > 0; i/=2) {
for (int j = 0; j < x.length; j++) {
sort(x,i,j);
}
}
}
public void sort(int[] x, int h, int r){
int tem = x[r];
r = r-h;
while (r>0 && tem<x[r]){
x[r+h] = x[r];
r = r-h;
}
x[r+h] = tem;
}
6.选择排序
规则:顾名思义有选择性的交换位置,第一趟找到最小值然后交换到第一个位置 第二趟找到第二小的值交换到第二个位置…
for (int i = 0; i < x.length; i++) {
int min = i;
for (int j = i; j < x.length; j++) {
if (x[min]>x[j]){
min = j;
}
}
int tem = x[min];
x[min] = x[i];
x[i] = tem;
}
7.堆排序
规则:先构建一个完全二叉树,大顶堆是大的在上面 小的在下面,小顶堆相反。构建完堆后 每次将顶部的节点取出放在相应位置 由最后一个叶子结点补上,然后再进行调整,调整完继续上一步步骤 循此往复直至堆的节点被取完则数组也有序了
public static void sort(int []arr){
//1.构建大顶堆
//由于完全二叉树的子节点数是总节点数的一半 所以非叶子节点坐标是从arr.length/2-1开始
for(int i=arr.length/2-1;i>=0;i--){
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
//2.将节点取出 并且调整
//循环的次数是数组的数量
for(int j=arr.length-1;j>0;j--){
swap(arr,0,j);//将堆顶元素与末尾元素进行交换
adjustHeap(arr,0,j);//重新对堆进行调整
}
}
public void adjustHeap(int []arr,int i,int length){
int temp = arr[i];//先取出当前元素i
//完全二叉树的子节点数是总节点数的一半 所以他的子节点是2i+1和2i+2
for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
k++;
}
if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
arr[i] = arr[k];
i = k;
}else{
break;
}
}
arr[i] = temp;//将temp值放到最终的位置
}
public void swap(int []arr,int a ,int b){
int temp=arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
8.计数排序
规则:利用元素的实际值来确定它们在输出数组中的位置
public void sort(int []arr){
if (arr==null || arr.length<2) return;
int max = arr[0];
int min = arr[0];
//找出数组中的最大值与最小值
for (int i = 0; i < arr.length; i++) {
if (arr[i]>max){
max=arr[i];
}
if (arr[i]<min){
min=arr[i];
}
}
//根据最大值最小值差建立数组
int[] count = new int[max-min+1];
//统计每个位置的参数数量
for (int i = 0; i < arr.length; i++) {
count[arr[i]-min] ++;
}
int index = 0;
//将参数放回到数组中
for (int i = 0; i < count.length; i++) {
for (int x = 0; x < count[i]; x++) {
arr[index++] = i+min;
}
}
}
9.桶排序
规则:创建一些均匀区间桶 将数组按照区间放入桶中 在分散排序 最后将桶中的参数依序输入到原数组就好
public void sort(int []arr){
if (arr==null || arr.length<2) return;
int max = arr[0];
int min = arr[0];
//找出数组中的最大值与最小值
for (int i = 0; i < arr.length; i++) {
if (arr[i]>max){
max=arr[i];
}
if (arr[i]<min){
min=arr[i];
}
}
//根据最大值最小值差和长度创建桶
List[] count = new List[(max - min)/arr.length+1];
//创建桶 并将参数放入桶中
for (int i = 0; i < arr.length; i++) {
int num = (arr[i] - min) / (arr.length);
if (count[num] == null){
count[num] = new ArrayList();
}
count[num].add(arr[i]);
}
// 对每个桶进行排序
for(int i = 0; i < count.length; i++){
Collections.sort(count[i]);
}
int index = 0;
//将参数放回到数组中
for (int i = 0; i < count.length; i++) {
if (count[i] != null){
for (int x = 0; x < count[i].size(); x++) {
arr[index++] = (int)count[i].get(x);
}
}
}
}
10.基数排序
规则:先按照个位数排序,然后按照十位数排序…直至按照最高位排序
public void sort(int []arr){
int[][] count = new int[10][arr.length];//创建十个桶
int[] order = new int[10];//每个桶里面的个数
int c = 1;
boolean flag = true;
while (flag){
flag = false;
//将数组按照位数放到到桶中
for (int i = 0; i < arr.length; i++) {
int tem = arr[i]/c;
if (tem>0){flag=true;}
int rem = tem%10;
count[rem][order[rem]++] = arr[i];
}
int index = 0;
//从桶中取出
for (int i = 0; i < 10; i++) {
if (order[i] != 0){
for (int j = 0; j < order[i]; j++) {
arr[index++] = count[i][j];
}
order[i] = 0;
}
}
c*=10;
}
}