经典排序算法

选泡插

快归堆希

桶计基

    private static void swap(int[] arr, int j, int i) {
        int temp = arr[j];
        arr[j] = arr[i];
        arr[i] = temp;
    }
选择排序

n^2 不稳

遍历找到最小的数,放到最前,依次

遍历一遍,最小值下标指向最小值,跟第一个数交换

for (int j = 0; j < arr.length; j++) {
	int minpos = 0;
	for (int i = 1; i < arr.length; i++) {
		if (arr[minpos] < arr[i]) {
		minpos = i;
		}
	swap(arr,i,minpos);
	}
}
冒泡排序

n^2 稳

第一个数与第二个数比较,谁大谁向后移,第一遍找到最大数

for (int j = 0 ; j<arr.length ;j++){
	for(int i=0; i<arr.length-1-j;i++){     //  j位后面的数已经有序,不用再排
		if(arr[i]>arr[i+1]){
			swap(arr,i,i+1);
		}
	}
}
插入排序

n^2 稳

第二个数与第一个数比较,谁小谁向前移

第三个数与其前面数比较,小向前移

(类似向前的冒泡排序)

for (int i = 1; i < arr.length ; i++) {
	for (int j = i ;j >0 ; j--){
		if(arr[j-1]>arr[j]){
			swap(arr,j-1,j);
         }
    }
}
希尔排序

取gap间隔的数排序

向后移动一位取间隔排序

间隔减小再排

到间隔为一再排,此时等于插入排序

for (int gap=arr.length/2; gap>0; gap /= 2){	//gap减小到1
	for (int j = 0; j < arr.length; j++) {      //以gap分组全部排序
		for (int i = j; i > gap-1; i-=gap) {    //以gap排一次,gap-1将arr[0]加入排序
			if (arr[i]<arr[i-gap])
			swap(arr,i,i-gap);
       }
    }
}
归并排序

N*logN:没有浪费比较信息

Java对象排序专用:TimSort 将数组分为多个小块,小块用binarySort排序,后用归并排序排小块

  • 第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

  • 第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置

  • 第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

  • 重复步骤3直到某一指针超出序列尾

  • 将另一序列剩下的所有元素直接复制到合并序列尾

import java.util.Arrays;

public class Test6 {
    public static void main(String[] args) {
        int[] arr = {5,2,8,4,3,6,7,9,1};
        sort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }

    public static void sort(int[] arr, int left, int right){
        //循环退出条件:只剩一个数返回,两个数开始排序
        if (left == right) return;
        //分成两组,递归直到只剩两个数进行merge排序,返回排好序的数组
        int mid = left + (right-left)/2;
        sort(arr,left,mid);
        sort(arr,mid+1,right);
        //merge排序,将有序的两数组排序,只有两个数时一个数当作一个数组
        merge(arr,left,mid+1,right);
    }

    public static void merge(int[] arr,int leftPtr,int rightPtr,int rightBound) {
        int mid = rightPtr-1;
        int[] temp = new int[rightBound-leftPtr+1];
        int i = 0;
        int saveLeftPtr = leftPtr;
        /*while (leftPtr<=mid && rightPtr<=rightBound){
            if (arr[leftPtr] <= arr[rightPtr]){
                temp[i] = arr[leftPtr];
                i++;
                leftPtr++;
            }else {
                temp[i] = arr[rightPtr];
                i++;
                rightPtr++;
            }
        }*/
        while (left<=mid && right<=rightBound)
        res[r++] = arr[left] < arr[right] ? arr[left++] : arr[right++];
        
        while (leftPtr <= mid)temp[i++] = arr[leftPtr++];//必须 <= ,放入最后一个数
        while (rightPtr <= rightBound)temp[i++] = arr[rightPtr++];

        //将结果存入arr数组,用于递归,同一个数组
        for (int j = 0; j < temp.length; j++) {
            arr[saveLeftPtr+j] = temp[j];
        }
    }
}
求解问题

求数组中累计比左边或右边大、小的数

计算小和

小和:数组中,每一个数左边比当前数小的数累加起来

使用归并排序:计算右边有几个数比当前数大

不重复,不漏地:计算范围内有几个数比其大,范围扩大后再计算

import java.util.Arrays;

public class SmallSum {
    public static void main(String[] args) {
        int[] arr = {1,4,2};
        int smallSum = smallSum(arr, 0, arr.length - 1);
        System.out.println(smallSum);
    }

    private static int smallSum(int[] arr,int start,int end) {
        if (start==end) return 0;
        int mid = start + (end-start)/2;
        int a = smallSum(arr, start, mid);
        int b = smallSum(arr, mid + 1, end);
        int c = merge(arr, start, mid + 1, end);
        return a+b+c;
    }

    private static int merge(int[] arr,int left,int right,int rightBound){
        int[] res = new int[rightBound-left+1];
        int r = 0;
        int mid = right-1;
        int saveLeft = left;
        int smallSum = 0;

        while (left<=mid && right<=rightBound)
            while (left<=mid && right<=rightBound){
                if (arr[left] < arr[right]){
                    res[r] = arr[left];
                    //小于时计算小和
                    smallSum += arr[left] * (rightBound-right+1); //计算比其大的数的个数需+1
                    r++;
                    left++;
                }else {
                    res[r] = arr[right];
                    r++;
                    right++;
                }
            }
            
        while (left<=mid)res[r++] = arr[left++];
        while (right<=rightBound)res[r++] = arr[right++];

        System.out.println(Arrays.toString(res));

        for (int i = 0; i < res.length; i++) {
            arr[saveLeft+i] = res[i];
        }
        return smallSum;
    }
}
计数排序

范围:count.length-1

import java.util.Arrays;

public class CountSort {
    public static void main(String[] args) {
        int[] arr = {5,1,8,3,6,9,2,7,4,2,3};
        int[] result = countSort(arr);
        System.out.println(Arrays.toString(result));
    }

    private static int[] countSort(int[] arr) {
        int[] result = new int[arr.length];
        int[] count = new int[10];
        for (int i = 0; i < arr.length; i++) {
            count[arr[i]]++;
        }
        for (int i = 0,n = 0; i < count.length; i++) {
            for (int j = 0; j < count[i]; j++) {
                result[n] = i;
                n++;
            }
        }
        return result;
    }
}

稳定

import java.util.Arrays;

public class CountSort {
    public static void main(String[] args) {
        int[] arr = {5,1,8,3,6,9,2,7,4,2,3};
        int[] result = countSort(arr);
        System.out.println(Arrays.toString(result));
    }

    private static int[] countSort(int[] arr) {
        int[] result = new int[arr.length];
        int[] count = new int[11];
        for (int i = 0; i < arr.length; i++) {
            count[arr[i]]++;
        }
        System.out.println(Arrays.toString(count));
        /*for (int i = 0,n = 0; i < count.length; i++) {
            for (int j = 0; j < count[i]; j++) {
                result[n] = i;
                n++;
            }
        }*/

        for (int i = 1; i < count.length; i++) {	//获取累加数组
            count[i] = count[i] + count[i-1];		//桶中相同数最后出现下标
        }
													
        for (int i = arr.length-1; i >= 0; i--) { //arr原数组倒叙复制到result,不改变相同数顺序
            result[--count[arr[i]]] = arr[i];	//累加数组下标减一就是相同数出现的最后一次,赋予
        }										//--count[arr[i]]数组最后出现的下标	
        return result;
    }
}
基数排序

先排个位数,相同放在一个桶中

再排十位数,相同放在一个桶中

import java.util.Arrays;

public class Test10 {
    public static void main(String[] args) {
        int[] arr = {122, 525, 634, 42, 15, 755, 124, 362};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    private static void sort(int[] arr) {
        int[] count = new int[10];
        int[] result = new int[arr.length];
        for (int i = 0; i < 3; i++) {
            int pow = (int) Math.pow(10, i);
            for (int j = 0; j < arr.length; j++) {
                int c = (arr[j] / pow) % 10;
                count[c]++;
            }
            for (int j = 1; j < count.length; j++) {
                count[j] = count[j] + count[j - 1];		//获取累加数组
            }

            for (int j = arr.length-1; j >= 0; j--) {
                int num = arr[j]/pow%10;				//num为0-9的count[]数组的下标
                result[--count[num]] = arr[j];	
            }
            Arrays.fill(count, 0);
            System.arraycopy(result, 0, arr, 0, result.length);
        }

    }
}

数组清零

int[] count = new int[10];
Arrays.fill(count,0);

数组复制

System.arrayCopy(srcBytes,0,destBytes,0,5);
// 将srcBytes源数组中 从0位 到 第5位之间的数值 copy 到 destBytes目标数组中,在目标数组的第0位开始放置.
//目标数组必须已经存在,且不会被重构,相当于替换目标数组中的部分元素。
快速排序
import java.util.Arrays;

public class QuickSort {
    public static void main(String[] args) {
        int[] arr = {2,5,1,5,8,6,9,4,1,1};
        sort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }

    private static void sort(int[] arr,int leftBound,int rightBound) {
        if (leftBound < rightBound && rightBound>=0) {
            int[] p = partition(arr, leftBound, rightBound);
            sort(arr, leftBound, p[0] - 1);
            sort(arr,p[1]+1,rightBound);
        }
    }

    private static int[] partition(int[] arr, int leftBound, int rightBound) {
        int pivot = rightBound;    //支点
        int i = leftBound;      //遍历数组下标
        while (i<rightBound){
            if (arr[i] < arr[pivot]){  //当前数小于支点:当前数与小于区域前一个数交换,小于区域扩大
                swap(arr,i,leftBound);
                leftBound++;
                i++;
                
            }else if (arr[i]>arr[pivot]){ //大于:与大于区域前一个数交换,大于区扩大,i不变
                swap(arr,leftBound,rightBound-1);
                rightBound--;
                
            }else {                     //等于:下一个数,小于区扩大
                leftBound++;
                i++;
            }
        }
        swap(arr,leftBound,pivot);
        return new int[]{leftBound,rightBound};
    }


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

Java源码

/*
             * Partitioning degenerates to the traditional 3-way
             * (or "Dutch National Flag") schema:
             *
             *   left part    center part              right part
             * +-------------------------------------------------+
             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
             * +-------------------------------------------------+
             *              ^              ^        ^
             *              |              |        |
             *             less            k      great
             *
             * Invariants:
             *
             *   all in (left, less)   < pivot
             *   all in [less, k)     == pivot
             *   all in (great, right) > pivot
             *
             * Pointer k is the first index of ?-part.
             */
            for (int k = less; k <= great; ++k) {
                if (a[k] == pivot) {
                    continue;
                }
               
                int ak = a[k];
                
                if (ak < pivot) { // Move a[k] to left part
                    a[k] = a[less];
                    a[less] = ak;
                    ++less;
                } else { // a[k] > pivot - Move a[k] to right part
                    while (a[great] > pivot) {
                        --great;
                    }
                    if (a[great] < pivot) { // a[great] <= pivot
                        a[k] = a[less];
                        a[less] = a[great];
                        ++less;
                    } else { // a[great] == pivot
                        /*
                         * Even though a[great] equals to pivot, the
                         * assignment a[k] = pivot may be incorrect,
                         * if a[great] and pivot are floating-point
                         * zeros of different signs. Therefore in float
                         * and double sorting methods we have to use
                         * more accurate assignment a[k] = a[great].
                         */
                        a[k] = pivot;
                    }
                    a[great] = ak;
                    --great;
                }
            }
堆排序
package sort.heap;

import java.util.Arrays;

//大根堆,堆排序
public class Heap {
    public static void main(String[] args) {

        int[] arr = {2, 6, 4, 8, 3};
        sort(arr);
    }

    private static void sort(int[] arr) {
        //逐个加入大根堆,根节点就是最大值
        for (int i = 0; i < arr.length; i++) {
            //每次加入数,heapInsert后都形成大根堆
            heapInsert(arr, i);
        }
        System.out.println(Arrays.toString(arr));

        //依次取出最大数
        int heapSize = arr.length;
        swap(arr, 0, --heapSize);
        while (heapSize > 0) {
            //heapify后根节点由孩子中大的占据,形成大根堆
            heapify(arr, 0, heapSize);
            //将尾部最后一个节点与根节点交换,最大值在数组尾部
            swap(arr, 0, --heapSize);
        }
        System.out.println(Arrays.toString(arr));
    }


    private static void heapify(int[] arr, int index, int heapSize) {
        int left = 2 * index + 1;

        //判断是否还有左孩子
        while (left < heapSize) {

            //判断两子谁大
            int largest = left + 1 < heapSize &&      //判断是否有右孩子,没有则left大
                    arr[left + 1] > arr[left] ? left + 1 : left;

            //判断父与子谁大
            largest = arr[largest] > arr[index] ? largest : index;

            //父是最大值,结束
            if (largest == index) {
                break;
            }

            swap(arr, largest, index);
            index = largest;
            left = index * 2 + 1;
        }
    }

    private static void heapInsert(int[] arr, int index) {

        while (arr[index] > arr[(index - 1) / 2]) {  //不比父大,或到0 停止
            swap(arr, index, (index - 1) / 2);
            index = (index - 1) / 2;
        }
    }

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值