算法导论(一)之排序

版权声明:欢迎大家转载,指正。 https://blog.csdn.net/yin__ren/article/details/83210823

一、 插入排序

1. 特点:

  • 易于实现
  • 适合小规模输入(<50)
  • 对近似排序好的输入效果好

2. 时间复杂度:

O ( n n ) O(n * n)

3. 伪代码

InsertionSort(A, n) {
	for i = 2 to n {
		key = A[i]
		j = i - 1
		while (j > 0) and (A[j] > key) {
			A[j+1] = A[j]
			j = j - 1
		}
		A[j+1] = key
	}
}

4. java 实现

public static void insertSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int tmp = arr[i];
            int j;
            for (j = i - 1; j >= 0 && tmp < arr[j]; j--) {
                arr[j + 1] = arr[j];
            }
            arr[j + 1] = tmp;
        }
    }

二、归并排序

1. 特点

  • 分割
  • 递归处理
  • 线性时间合并

2. 时间复杂度

O ( n l o g n ) O(n * logn)

3. 伪代码

MERGE(A,p,q,r){//p,q,r 是数组下标,p<=q<=r
	n1 ← q – p + r
	n2 ← r – q
	let L and R 为左右临时数组
	for i = 1..n1
		do L[i] ← A[p + i – 1]
	for j = 1..n2
		do R[j] ← A[q + j]
	//A:(结束标志)
	L[n1 + 1] ← ∞
	R[n2 + 1] ← ∞
	i ← 1
	j ← 1
	for k = p to r
		do if L[i] ≤ R[j]
			then A[k] ← L[i]
			i ← i + 1
		else A[k] ← R[j]
			j ← j + 1
}
MergeSort(A, p, r){
	if p < r
		//Split the input into 2 pieces of approximately equal size
		q ← (p + r) / 2
		//Recursively sort the two halves
		MergeSort(A, p, q)
		MergeSort(A, q + 1, r)
		//Merge the two sorted subsequences
		Merge(A, p, q, r)
}

4. java 实现

/**
     * 分治
     *
     * @param arr
     * @param left
     * @param right
     * @param tmp
     */
    private static void sort(int[] arr, int left, int right, int[] tmp) {
        if (left < right) {
            int mid = (left + right) / 2;
            sort(arr, left, mid, tmp);//左归并
            sort(arr, mid + 1, right, tmp);//右归并
            merge(arr, left, mid, right, tmp);
        }
    }

    /**
     * 归并核心算法
     *
     * @param arr
     * @param left
     * @param mid
     * @param right
     * @param tmp
     */
    private static void merge(int[] arr, int left, int mid, int right, int[] tmp) {
        int i = left;//左序列
        int j = mid + 1;//右序列
        int t = 0;//tmp
        while (i <= mid && j <= right) {//归并
            if (arr[i] <= arr[j]) {
                tmp[t++] = arr[i++];
            } else {
                tmp[t++] = arr[j++];
            }
        }
        while (i <= mid) {//将左边剩余元素填入
            tmp[t++] = arr[i++];
        }
        while (j <= right) {//将右边剩余元素填入
            tmp[t++] = arr[j++];
        }
        t = 0;
        while (left <= right) {//将 tmp 中的元素拷贝如原数组中
            arr[left++] = tmp[t++];
        }
    }

三、计数排序

1. 特点:

  • 小范围整数的排序
  • 稳定的:相等的输入元素的位置先后顺序在排列后输出中的先后顺序不变

2. 时间复杂度

θ ( n + k ) \theta(n + k)

3. 伪代码

//A 输入数组,B 存放排序的输出,C 提供临时储存空间
COUNTING-SORT(A, B, n, k){//假设n个输入元素为0-k之间的整数
	let C[0..k] be a new array
	for i ← 0 to k
		do C[ i ] ← 0
	//计算 C[i]包含等于i的元素的个数
	for j ← 1 to n
		do C[A[ j ]] ← C[A[ j ]] + 1
	//计算 C[i] 包含小于或等于i的元素的个数
	for i ← 1 to k
		do C[ i ] ← C[ i ] + C[i -1]
	for j ← n downto 1
		B[C[A[ j ]]] ← A[ j ]
		C[A[ j ]] ← C[A[ j ]] - 1
}

4. java 代码实现

public static void countSort(int[] input) {
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < input.length; i++) {
            max = Math.max(max, input[i]) + 1;
        }
        int[] output = new int[input.length];
        int[] tmp = new int[max];
        for (int i = 0; i < tmp.length; i++) {
            tmp[i] = 0;
        }
        for (int j = 0; j < input.length; j++) {
            tmp[input[j]]++;
        }
        int t = 0;
        for (int k = 0; k < tmp.length; k++) {
            while (tmp[k] > 0) {
                output[t++] = k;
                tmp[k]--;
            }
        }
        for (int i = 0; i < input.length; i++) {
            input[i] = output[i];
        }
    }

四、基数排序

1. 特点

  • 扩大了可排序的整数范围

2. 时间复杂度

O ( n k ) O(n * k)

3. 伪代码

RADIX-SORT(A,d){
	for i = 1 to d
		use a table sort to sort array A on digit i
}

4. Java 代码实现

public static void radixSort(int[] arr) {
        //防止越界
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < arr.length; i++) {//计算最大值
            max = Math.max(max, arr[i]);
        }
        final int bucketNum = 10;
        List<ArrayList<Integer>> bucket = new ArrayList<>(bucketNum);
        for (int i = 0; i < bucketNum; i++) {
            bucket.add(new ArrayList<Integer>());
        }
        for (int i = 0; i < Math.log10(max) + 1; i++) {
            int digest = (int) (1 * Math.pow(10, i));
            for (int j = 0; j < arr.length; j++) {
                int tmp = (arr[j] / digest) % 10;
                bucket.get(tmp).add(arr[j]);
            }
            int t = 0;
            for (int j = 0; j < bucketNum; j++) {
                for (int k = 0; k < bucket.get(j).size(); k++) {
                    arr[t++] = bucket.get(j).get(k);
                }
                bucket.get(j).clear();
            }
        }
    }

五、桶排序

1. 特点

  • 将[0, 1) n等分,称为空桶
  • 将n个输入分派到这些空桶之中
  • 每个桶内排序
  • 按顺序遍历每个桶中的元素

2. 时间复杂度

O ( n ) O(n)

3. 伪代码

BUCKET-SORT(A){
	n = A.length
	let B[0..n-1] be a new array
	for i ← 1 to n
		insert A[i] into list B[nA[i]] (注意下标)
	for i ← 0 to n - 1
		sort list B[i] with insertion sort (桶内插入排序)
	concatenate lists B[0], B[1], . . . , B[n -1]together in order
	return the concatenated lists
}

4. java 代码实现

public static void bucketSort(int[] arr) {
        //防止越界
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < arr.length; i++) {//计算最大值与最小值
            max = Math.max(max, arr[i]);
            min = Math.min(min, arr[i]);
        }
        //桶数
        int bucketNum = (max - min) / arr.length + 1;
        List<ArrayList<Integer>> bucket = new ArrayList<>(bucketNum);
        for (int i = 0; i < bucketNum; i++) {//初始化每个桶
            bucket.add(new ArrayList<Integer>());
        }
        for (int i = 0; i < arr.length; i++) {//将元素放入指定的桶中
            int num = (arr[i] - min) / arr.length;
            bucket.get(num).add(arr[i]);
        }
        int t = 0;
        for (int i = 0; i < bucketNum; i++) {//对每个桶进行排序
            Collections.sort(bucket.get(i));
            for (int k = 0; k < bucket.get(i).size(); k++) {//将桶中排好序的元素放入原数组中
                arr[t++] = bucket.get(i).get(k);
            }
        }
    }

六、快速排序

1. 特点

2. 时间复杂度

O ( n l o g n ) O(n * logn)

3. 伪代码

QUICKSORT(A,p,r){
	if p < r
		q = PARTITION(A,p,r)
		QUICKSORT(A,p,q-1)
		QUICKSORT(A,q+1,r)
}

PARTITION(A,p,r){
	x = A[r]
	i = p - 1
	for j = p to r - 1
		if A[j] <= x
			i = i + 1
			exchange A[i] with A[j]
	exchange A[i + 1] with A[r]
	return i + 1
}

4. Java 代码实现

private static void quickSort(int[] arr, int left, int right) {
        if (left > right) {
            return;
        }
        int index = arr[left], tmp;
        int i = left, j = right;
        while (i != j) {
            while (arr[j] >= index && i < j) {
                j--;
            }
            while (arr[i] <= index && i < j) {
                i++;
            }
            if (i < j) {
                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
            }
        }
        arr[left] = arr[i];
        arr[i] = index;
        quickSort(arr, left, i - 1);
        quickSort(arr, i + 1, right);
    }

七、随机快速排序

1. 特点

  • 随机性
  • 对数组划分比较均衡

2. 时间复杂度

O ( n l o g n ) O(n * log n)

3. 伪代码

RANDOMMIZED-QUICKSORT(A,p,r){
	if p < r
		q = RANDOMMIZED-PARTITION(A,p,r)
		RANDOMMIZED-QUICKSORT(A,p,q - 1)
		RANDOMMIZED-QUICKSORT(A,q + 1,r)
}

RANDOMMIZED-PARTITION(A,p,r){
	i = RANDOM(p,r)
	exchange A[r] with A[i]
	return PARTITION(A,p,r)
}

4. Java 代码实现

private static void randomQuickSort(int[] arr, int left, int right) {
        if (left > right) {
            return;
        }
        Random random = new Random();
        int random_index = (int) (Math.random() * (right - left + 1)) + left;
        int swap = arr[random_index];
        arr[random_index] = arr[left];
        arr[left] = swap;


        int index = arr[left], tmp;
        int i = left, j = right;
        while (i != j) {
            while (arr[j] >= index && i < j) {
                j--;
            }
            while (arr[i] <= index && i < j) {
                i++;
            }
            if (i < j) {
                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
            }
        }
        arr[left] = arr[i];
        arr[i] = index;
        randomQuickSort(arr, left, i - 1);
        randomQuickSort(arr, i + 1, right);
    }

八、堆排序

1. 实现最大堆

1. 伪代码

MAX-HEAPIFY(A,i)
	l = LEFT(i)
	r = RIGHT(i)
	if l <= A.heap-size and A[l] > A[i]
		largest = l
	else largest = i
	if r <= A.heap-size and A[r] > A[largest]
		largest = r
	if largest != i
		exchange A[i] and A[largest]
		MAX-HEAPIFY(A,largest)

2. 时间复杂度

T ( n ) = O ( l o g n ) T(n) = O(log n)

3. java 代码实现

//使第 i 个节点满足最大堆规则
public static int[] maxHeap(int[] arr, int i) {
        int large = i;
        if (2 * i < arr.length && arr[2 * i] > arr[i]) {
            large = 2 * i;
        }
        if (2 * i + 1 < arr.length) {
            if (arr[2 * i + 1] > arr[i] && arr[2 * i + 1] > arr[2 * i]) {
                large = 2 * i + 1;
            }
        }
        if (large != i) {
            HeapSort.swap(arr, i, large);
            maxHeap(arr, large);
        }
        return arr;
    }

    private static void swap(int[] arr, int a, int b) {
        int tmp = arr[a];
        arr[a] = arr[b];
        arr[b] = tmp;
    }

	//对数组进行扩容,使其以 1 为起始下标
    private static int[] increaseArr(int[] arr) {
        int[] result = new int[arr.length + 1];
        for (int i = 1; i < result.length; i++) {
            result[i] = arr[i - 1];
        }
        return result;
    }

    public static void main(String[] args) {
        int[] arr = {16, 4, 10, 14, 7, 9, 3, 2, 8, 1};
        arr = HeapSort.increaseArr(arr);
        arr = HeapSort.maxHeap(arr, 2);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

非递归代码:

public static int[] maxHeap2(int[] arr,int i){
        while (2 * i < arr.length){
            int j = 2 * i;
            if (j + 1 < arr.length && arr[j + 1] > arr[j]){
                j += 1;
            }
            if (arr[i] >= arr[j]){
                break;
            }
            HeapSort.swap(arr,i,j);
            i = j;
        }
        return arr;
    }

2. 建最大堆

1. 伪代码

BUILD-MAX-HEAP(A)
	A.heap-size = A.length
	for i = A.length / 2 downto 1
		MAX-HEAPIFY(A,i)

2. 时间复杂度

T ( n ) = O ( n ) T(n) = O(n)

3. java 代码实现

public static int[] buildMaxHeap(int[] arr) {
        arr = HeapSort.increaseArr(arr);
        for (int i = arr.length / 2; i >= 1; i--) {
            HeapSort.maxHeap(arr, i);
        }
        return arr;
    }

 public static void main(String[] args) {
        int[] arr = {16, 4, 10, 14, 7, 9, 3, 2, 8, 1};
        arr = HeapSort.buildMaxHeap(arr);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

3. 堆排序

1. 伪代码

HEAPSORT(A)
	BUILD-MAX-HEAP(A)
	for i = A.length downto 2
		exchange A[1] with A[i]
		A.heap-size = A.heap-size - 1
		MAX-HEAPIFY(A,1)

2. 时间复杂度

T ( n ) = n l o g n T(n) = n * logn

扫描二维码关注公众号,回复: 3660675 查看本文章

3. java 代码实现

public static int[] heapSort(int[] arr) {
        int[] result = new int[arr.length];
        arr = HeapSort.buildMaxHeap(arr);
        for (int i = arr.length - 1; i >= 1; i--) {
            HeapSort.swap(arr, 1, i);
            result[i - 1] = arr[i];
            arr = HeapSort.decreaseArr(arr);
            arr = HeapSort.maxHeap(arr,1);
        }
        return result;
    }

public static void main(String[] args) {
        int[] arr = {16, 4, 10, 14, 7, 9, 3, 2, 8, 1};
        arr = HeapSort.heapSort(arr);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

猜你喜欢

转载自blog.csdn.net/yin__ren/article/details/83210823