内部排序

稳定:不改变同等大小的顺序,7,6(1),6(2),5 ,不会变成6(2),6(1), 稳定排序(需谨慎关注=)
内部排序:内存中完成
外部排序:数据量大,需外存访问,可内存中放一部分,先对一部分排序,后面再调取数据排序
最好:12345 最差:54321 有些时候需计算最好最差情况的时间复杂度
1 冒泡排序:多次比较,一次比较一半概率交换,先把最大的放右边

public void bubbleSort(int []a){
           int len=a.length;
           for(int i=0;i<len;i++){  // i<len-1也可以,len-1里层循环无法运行
               for(int j=0;j<len-i-1;j++){//注意第二重循环的条件
                   if(a[j]>a[j+1]){  // 相等不交换,保证稳定性
                       int temp=a[j];
                       a[j]=a[j+1];
                       a[j+1]=temp;
                   }
               }
           }
       }

比较: n(n-1)/2 交换:n(n-1)/4, 稳定

2 简单选择排序(选择排序类别下):找出最小的,与第一个交换,也可以找最大的与最后一个交换

public void selectSort(int[]a){
        int len=a.length;
        for(int i=0;i<len;i++){   //循环次数, i<len-1也可以
            int position=i;
            for(int j=i+1;j<len;j++){  //找到最小位置
                if(a[j]<a[position]){
                    position=j;
                }
            }
            int temp=a[position];
            a[position]=a[i];//进行交换
            a[i]=temp;
        }
    }

比较: n(n-1)/2 交换:n-1 , 不稳定(5 8 5 2 9,第一个5和2交换,排在第二个5后面了)

3 直接插入排序(插入排序类别下):设想已存在有序序列,一个一个插入

public static void insertionSort(int[] arr) {
    for (int i = 1; i < arr.length; i++) {
        int j = i;  // j初始为i,减减到1,当然碰到arr[j - 1]不大于arr[j]也退出
        while (j > 0 && arr[j] < arr[j - 1]) {
            swap(arr,j,j-1);
            j--;
        }
    }
}

比较: n(n-1)/4 (平均估值) 交换:n(n-1)/4 (平均估值,应该少于比较次数,arr[j] >= arr[j - 1]最后一次比较不交换),稳定

4 希尔排序(插入排序类别下)
考虑到直接插入排序在比较有序的情况下效率很高,所以先按某增量序列进行直接插入排序,然后不断减少增量,最后全体元素进行直接插入排序

public static void sort(int[] a) {
for (int d = a.length / 2; d >= 1; d = d / 2) { // 初定为数组长度的一半,按一半减小,如5变成2,最小到1
    for (int i = 0; i < d; i++) {
	   for (int j = d + i; j < a.length; j = j + d) { // 开始直接插入排序
	     int k = j;
	     while (k >= d && a[k] < a[k - d]) {
		   int temp = a[k];
		   a[k] = a[k - d];
		   a[k - d] = temp;
		   k = k - d;
	    }
	 }
    }
 }
}

时间复杂度依赖序列选取, 一般在 O(N^1.3) 到 O(N^2) ,不稳定(1977,按步长2来后面的7就去前面了)

5 快速排序:找基准(一般首位),左边小于(等于)基准,右边大于(等于)基准,然后分别对左右排序
若选择首位作为基准,那么右哨兵先出动,两哨兵碰头(右先出动,碰头位置是小于基准的数)的位置和基准交换

void quicksort(int[] a, int left, int right) {
	if(left > right){ // left>=right 也可以,一个数其实也没必要排序
		return;
	}
    int  temp = a[left]; //temp中存的就是基准数
    int i = left;
    int j = right;
    while(i != j) { //顺序很重要,要先从右边开始找
    	while(a[j] >= temp && i < j){  // a[j]=temp,不用交换,留在原位置,当然算法本身不稳定,交换了也问题不大
    		j--;
    	}
    	while(a[i] <= temp && i < j){
    		i++;       
    	}
    	if(i < j) //交换i,j   i=j 已经碰头,没必要交换,马上就出去
    	{
    		int t = a[i];
    		a[i] = a[j];
    		a[j] = t;
    	}
    }
    //最终将基准数归位
    a[left] = a[i];
    a[i] = temp;
    quicksort(a, left, i-1);//继续处理左边的,这里是一个递归的过程
    quicksort(a, i+1, right);//继续处理右边的 ,这里是一个递归的过程
}

平均O(NlogN) (8个数,拆分2份,比较8次,拆分4份,比较8次,拆分8份,比较8次),最差O(n^2),最差(总是N个数分为1和N-1),不稳定(5774239,两个7换到右边交换了顺序)

6 归并排序:考虑对已经排好序的两个序列进行合并

   public static void sort(int[] a, int left, int right) {
	if (left >= right) { // =一个数没必要排序,>一般不会出现,可能会传错
	    return;
	}
	int middle = (left + right) / 2;
	sort(a, left, middle);
	sort(a, middle + 1, right);
	int tmp[] = new int[right - left + 1];
	int i = left;
	int j = middle + 1;
	int k = 0;
	while (i <= middle && j <= right) {
	    if (a[i] <= a[j]) {
		tmp[k++] = a[i++];
	    } else {
		tmp[k++] = a[j++];
	    }
	}
	while (i <= middle) {
	    tmp[k++] = a[i++];
	}
	while (j <= right) {
	    tmp[k++] = a[j++];
	}
	int n = 0;
	for (int m = left; m <= right; m++) {
	    a[m] = tmp[n++];
	}
    }

时间复杂度各种情况下都为O(NlogN) ,但是需要O(N)空间,稳定

7堆排序:
堆:完全二叉树,对任一节点,其子节点小于等于它(大顶堆),或者大于等于它(小顶堆)

public static void sort(int[] a) {
for (int i = (a.length - 1) / 2; i >= 0; i--) { // 无论最后的叶子节点是左节点还是右节点,其父节点都为(a.length - 1) / 2
    heapAdjust(a, i, a.length);
}
for (int i = a.length - 1; i >= 1; i--) { // i=0 没必要自己和自己交换
    int tmp = a[0];
    a[0] = a[i];
    a[i] = tmp;
    heapAdjust(a, 0, i); // 堆随着i不断减小
}
}

public static void heapAdjust(int[] a, int i, int length) { // 数组a,长度length所构成的堆结构里,从i开始向下调整
while (true) { // 不断向下调整
    int tmp = 0;
    if (2 * i + 1 >= length) { // 无左子节点,退出
	break;
    }
    if (2 * i + 2 >= length) { // 无右子节点,只有左子节点,可能需交换后退出
	if (a[i] < a[2 * i + 1]) {
	    tmp = a[i];
	    a[i] = a[2 * i + 1];
	    a[2 * i + 1] = tmp;
	}
	break;
    }
    if (a[i] >= a[2 * i + 1] && a[i] >= a[2 * i + 2]) { // i最大,无需交换,退出
	break;
    } else if (a[2 * i + 1] >= a[2 * i + 2]) { // 左子节点最大,和左子交换,左子继续调整
	tmp = a[i];
	a[i] = a[2 * i + 1];
	a[2 * i + 1] = tmp;
	i = 2 * i + 1;
    } else { // 右子节点最大,和右子交换,右子继续调整
	tmp = a[i];
	a[i] = a[2 * i + 2];
	a[2 * i + 2] = tmp;
	i = 2 * i + 2;
    }
}
}

时间复杂度各种情况下都为O(NlogN) ,不稳定

8基数(桶)排序: 先个位排,然后放回原数组,然后十位排

public static void sort(int[] a, int d) { //最大位数传入
int[][] tmp = new int[10][a.length]; //10个桶
int[] order = new int[10];  //记录每个桶有多少个数,初始为0
int m = 1;
int n = 1;
int k = 0;
while (m <= d) {
    for (int i = 0; i < a.length; i++) { // 入桶
	int j = (a[i] / n) % 10; // 937取3,先除10得到93,93取个位按10取商
	tmp[j][order[j]] = a[i]; 
	order[j]++;
    }
    for (int i = 0; i < 10; i++) { //已入桶数据(一定程度有序)放回原数组
	if (order[i] != 0) { 
	    for (int j = 0; j < order[i]; j++) {
		a[k++] = tmp[i][j];
	    }
	    order[i] = 0; //放完记得桶内计数清0
	}
    }
    k = 0;
    n *= 10;
    m++;
}
}

时间复杂度各种情况下大致为O(N∗M) ,即数据个数乘数据位数, 空间复杂度为O(N),其实为10N, 稳定

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值