排序算法整理


各算法时间、空间复杂度和稳定性:::

来源:https://blog.csdn.net/shihuboke/article/details/79387523

如果某个排序算法能保证:对于待排序的数组中重复元素排序后相对顺序不变,就称这种排序算法是稳定的。否则不稳定

1.快速排序

思路:
确定一个数为分界线,在其左边的全比它小,在它右边的全比他大;
再分别对其左右两边进行快排(递归)
代码:

public static void quickSort(int[] arr, int start, int end){
		if(start >= end)
			return;
		int left = start, right = end;
		int key = arr[left];//一般取第一个元素作为分界线
		//当left = right, arr[left] = key
		while(left < right){
			//先从后往前找
			while(arr[right] >= key && left < right){//从后往前找第一个小于key的数
				right--;
			}
			//将更小的数放到右边
			arr[left] = arr[right];
			while(arr[left] <= key && left < right){//从前往后找第一个大于key的数
				left++;
			}
			//将更大的数放到左边
			arr[right] = arr[left];

		}
		arr[left] = key;//分界线,left左边都是比key小的,left右边都是比key大的
		quickSort(arr, start, left - 1); // 递归调用 
        quickSort(arr, left + 1, end);
	}

主函数:

class quickSort{
	public static void main(String[] args){
		//int arr[] = new int[]{3,13,3,7,9,122344,4656,34,34,4656,5,6,7,8,9,343,57765,3,12321};
		int arr[] = new int[]{13,57765,2,2,2,12321};            
		int len = arr.length-1;        
		quickSort(arr,0,len);        
		for (int i:arr) {            
			System.out.print(i+"\t");        
		}    
	}
}

时间复杂度:
最优复杂度:O(nlog(n))
平均复杂度:O(nlog(n))
最差复杂度:O(n^2)如,降序的数组要求排成升序,这种情况和冒泡排序一样
空间复杂度:O(log(n))
稳定性:不稳定,从后往前找,找到一个比key小的,就交换,相同元素的顺序必然交换,如{3,2,2,5}

2.插入排序

思路:
类似打扑克牌的时候排序,将待插入的牌插入到已有序的牌中
第一次for循环中起始位 i = 1是从第二张牌开始插入操作
第二次for循环的起始位是 j = i 就是每次把这一位置的元素插入,从后往前比较,因为本次排序前只有前 i-1 位是有序的

代码:

	public static void insertSort(int[] arr){
		int len = arr.length;
		for(int i = 1; i < len; i++){//要插入的牌
			for(int j = i; j > 0 && arr[j] < arr[j - 1]; j--){//找要插入的位置,判断条件这么写,最优时间复杂度才是O(n)
				int temp = arr[j];
				arr[j] = arr[j - 1];
				arr[j - 1] = temp;
			}
		}
	} 

复杂度分析:
时间复杂度:
最优时间复杂度:O(n),已经有序
最差时间复杂度:O(n^2)
平均时间复杂度:O(n^2)
空间复杂度:O(1)

3.冒泡排序:

思路:
按位置重复遍历,两两比较
注意第二个循环的起始位是 j = 0,而终止位是len - 1 - i,这样的目的是每轮排序都使一个最大元素沉底(数组最后端,而这个元素则是本轮排序中的最大值)
它重复地走访过要排序的数列,一次比较相邻两个元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。
代码:

	public static void bubbleSort(int[] arr){
		int len = arr.length;
		for(int i = 0; i < len - 1; i++){
			for(int j = 0; j < len - 1 - i; j++){
				if(arr[j] > arr[j + 1]){//升序排列,把这个条件判断放在for循环里,就能实现最优时间复杂度为O(n)
					int temp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = temp;
				}
			}
		}
	}

注意,java不可以定义一个交换函数,因为Java中不能直接操作指针变量,int、double、float等基本类型函数传参的时候都是值传递,也就是传入函数的只是原来变量的一个副本,所以在函数中交换是副本,并达不到交换的目的。
参考:https://blog.csdn.net/cflys/article/details/71102021
在这里插入图片描述

不能交换,基本类型传参时是值传递的
	public static void swap(int a, int b){
		int temp = a;
		a = b;
		b = temp;
	}

复杂度分析:
时间复杂度:
最优时间复杂度:O(n),已经有序
最差时间复杂度:O(n(n-1)/2) = O(n^2)
平均时间复杂度:O(n^2)
空间复杂度:O(1)

4.选择排序:

思路:
每轮找到最小值,放在已排序列末尾
它的工作原理如下。
首先在还没有排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
代码:

public static void selectSort(int[] arr){
	int len = arr.length;	
	for(int i = 0; i < len; i++){
		int minIndex = i;//找到此轮最小的索引
		for(int j = i; j < len; j++){
			if(arr[j] < arr[minIndex]){//有等于号,不稳定,没有等于号,稳定
				minIndex = j;
			}
		}
		int temp = arr[i];
		arr[i] = arr[minIndex];
		arr[minIndex] = temp;
	}
}

复杂度分析:
时间复杂度:
最优时间复杂度:O(n^2)
最差时间复杂度:O(n^2)
平均时间复杂度:O(n^2)
空间复杂度:O(1)

5.归并排序

将数组不断二分,直到最小长度为1,再进行归并操作
代码:

	//归并排序
    public static int[] mergeSort(int[] arr, int start, int end) {
        if (start >= end)
            return new int[]{arr[start]};
         
        int mid = start + (end - start) / 2;
        int[] leftArr = mergeSort(arr, start, mid); //左有序数组
        int[] rightArr = mergeSort(arr, mid + 1, end); //右有序数组
        int[] ans = new int[leftArr.length + rightArr.length]; //新有序数组
         
        int index = 0, leftStart = 0, rightStart = 0; 
        while (leftStart < leftArr.length && rightStart < rightArr.length) {
            ans[index++] = leftArr[leftStart] < rightArr[rightStart] ? leftArr[leftStart++] : rightArr[rightStart++];
        }
        //左右有序数组中可能有一个剩余,把剩余的元素加上
        while (leftStart < leftArr.length)
            ans[index++] = leftArr[leftStart++];
        while (rightStart < rightArr.length)
            ans[index++] = rightArr[rightStart++];   

        return ans;
    }

6.堆排序

public class HeapSort implements IArraySort {

    @Override
    public int[] sort(int[] sourceArray) throws Exception {
        // 对 arr 进行拷贝,不改变参数内容
        int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

        int len = arr.length;

        buildMaxHeap(arr, len);

        for (int i = len - 1; i > 0; i--) {
            swap(arr, 0, i);
            len--;
            heapify(arr, 0, len);
        }
        return arr;
    }

    private void buildMaxHeap(int[] arr, int len) {
        for (int i = (int) Math.floor(len / 2); i >= 0; i--) {
            heapify(arr, i, len);
        }
    }

    private void heapify(int[] arr, int i, int len) {
        int left = 2 * i + 1;
        int right = 2 * i + 2;
        int largest = i;

        if (left < len && arr[left] > arr[largest]) {
            largest = left;
        }

        if (right < len && arr[right] > arr[largest]) {
            largest = right;
        }

        if (largest != i) {
            swap(arr, i, largest);
            heapify(arr, largest, len);
        }
    }

    private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}

最大堆

public class HeapSort1 {
 
    public static void main(String[] args) {
        int[] a = new int[]{16, 25, 7, 32, 6, 9};
        heapSort(a);
        System.out.println(Arrays.toString(a));
    }
 
    /**
     * 构造大顶堆
     * @param arr 待调整数组
     * @param size 调整多少
     * @param index 调整哪一个 最后一个叶子节点的父节点开始调整
     */
    public static void maxHeap(int arr[], int size, int index) {
 
        //左子节点
        int leftNode = 2 * index + 1;
        //右子节点
        int rightNode = 2 * index + 2;
 
        int max = index;//假设自己最大
 
        //分别比较左右叶子节点找出最大
        if(leftNode < size && arr[leftNode] > arr[max]) {//如果左侧叶子节点大于max则将最大位置换成leftNode并且递归需要限定范围为数组长度,
            max = leftNode;//将最大位置改为左子节点
        }
 
        if(rightNode < size && arr[rightNode] > arr[max]) {//如果左侧叶子节点大于max则将最大位置换成rightNode
            max = rightNode;//将最大位置改为右子节点
        }
 
        //如果不相等就需要交换
        if(max != index) {
            int tem = arr[index];
            arr[index] = arr[max];
            arr[max] = tem;
            //如果下边还有叶子节点并且破坏了原有的堆。需要重新调整
            maxHeap(arr, size, max);//位置为刚才改动的位置;
        }
    }
 
    /**
     * 需要将最大的顶部与最后一个交换
     * @param arr
     */
    public static void heapSort(int arr[]) {
        int start = (arr.length - 1)/2;//开始位置最后一个非叶子节点,最后一个叶子节点的父节点
        for(int i = start; i>=0; i--) {
            maxHeap(arr, arr.length, i);
        }
 
        //最后一个跟第一个进行调整
        for(int i = arr.length-1; i>0; i--) {//因为数组从零开始的,所以最后一个是数组长度减一
            int temp = arr[0];//最前面的一个
            arr[0] = arr[i];//最后一个
            arr[i] = temp;
            //调整后再进行大顶堆调整
            maxHeap(arr, i, 0);
        }
    }
}

最小堆

public class HeapSortMin {
    public static void main(String[] args) {
        int[] a = new int[]{16, 25, 7, 32, 6, 9};
        heapSort(a);//小顶堆
        System.out.println(Arrays.toString(a));
    }
 
    /**
     * 构造小顶堆
     * @param arr 待调整数组
     * @param size 调整多少
     * @param index 调整哪一个 最后一个叶子节点的父节点开始调整
     */
    public static void minHeap(int arr[], int size, int index) {
 
        //左子节点
        int leftNode = 2 * index + 1;
        //右子节点
        int rightNode = 2 * index + 2;
 
        int min = index;//假设自己最小
 
        //分别比较左右叶子节点找出最小
        if(leftNode < size && arr[leftNode] < arr[min]) {//如果左侧叶子节点小于min则将最小位置换成leftNode并且递归需要限定范围为数组长度,
            min = leftNode;//将最小位置改为左子节点
        }
 
        if(rightNode < size && arr[rightNode] < arr[min]) {//如果左侧叶子节点小于min则将最小位置换成rightNode
            min = rightNode;//将最小位置改为右子节点
        }
 
        //如果不相等就需要交换
        if(min != index) {
            int tem = arr[index];
            arr[index] = arr[min];
            arr[min] = tem;
            //如果下边还有叶子节点并且破坏了原有的堆。需要重新调整
            minHeap(arr, size, min);//位置为刚才改动的位置;
        }
    }
 
    /**
     * 需要将最小的顶部与最后一个交换
     * @param arr
     */
    public static void heapSort(int arr[]) {
        int start = (arr.length - 1)/2;//开始位置最后一个非叶子节点,最后一个叶子节点的父节点
        for(int i = start; i>=0; i--) {
            minHeap(arr, arr.length, i);
        }
 
        //最后一个跟第一个进行调整
        for(int i = arr.length-1; i > 0; i--) {
            int temp = arr[0];//最前面的一个
            arr[0] = arr[i];//最后一个
            arr[i] = temp;
            //调整后再进行小顶堆调整
            minHeap(arr, i, 0);
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值