基础排序

选择排序

指针表示法
void choose_sort(int* arr, int n) {
    for (int i = 0; i < n; i++) {
        int minIndex = i;
        for (int j = i + 1; j < n; j++) {
            if (*(arr + j) < *(arr + minIndex)) {
                minIndex = j;
            }
        }
        swap(arr, minIndex, i);
    }
}

数组表示法
void selectionSort(int arr[],int n){
	for(int i=0;i<n;i++){
		int minIndex = i;
		for(int j=i+1;j<n;j++){
			if(arr[j] < arr[minIndex]){
				minIndex = j;
			}
		}
		swap(arr,i,minIndex);
	}
}

冒泡排序

void bubbleSort(int* arr,int n){
	for(int i=n-1;i>0;i--){
		for(int j=0;j<i;j++){
			if(arr[j] > arr[j+1]){
				swap(arr,j,j+1);
			}
		}
	}
}

模板(泛型)

template <typename T>
void selectionSort(T arr[],int n){
	for(int i=0;i<n;i++){
		int minIndex = i;
		for(int j=i+1;j<n;j++){
			if(arr[j] < arr[minIndex]){
				minIndex = j;
			}
		}
		swap(arr,i,minIndex);
	}
}
甚至可以对自定义类型进行排序,如定义结构体:
struct Student {
    string name;
    int score;
    
    重载 < 号,为了自定义排序。
    bool operator<(const Student& otherStudent) {
        return score < otherStudent.score;
    }
    
	重载 << 输出,cout直接输出student结构体类型。
    friend ostream& operator<<(ostream& os, const Student& student) {
        os << "student:" << student.name << " " << student.score << endl
        return os;
    }
};

随机生成算法

<ctime> <cassert> <iostream>
assert 如果出现错误则中止,需要头文件包含 <cassert>
int* generateRandomArray(int n, int rangeL, int rangeR) {
    assert(rangeL <= rangeR);
    int* arr = (int*)malloc(sizeof(int) * n);
    srand((unsigned)time(NULL));
    for (int i = 0; i < n; i++) {
        *(arr + i) = rand() % (rangeR - rangeL + 1) + rangeL;
    }
    return arr;
}

插入排序

普通的插入排序,只是交换。
void insertSort(int* arr,int n){
	for(int i=1;i<n;i++){
		for(int j=i;j>0;j--){
			if(arr[j] < arr[j-1]){
				swap(arr,j,j-1);
			}
		}
	}
}

加强插入排序,仅仅当arr[j-1] 比 arr[j] 大的时候才修改 ,交换改成赋值。
设定一个temp为 arr[i],如果arr[j-1] 比 temp大,就说明该进行插入排序,直到后退到该放置temp的位置,然后内循环结束,在arr[j]处放置 temp。

void insertSort(int* arr,int n){
	for(int i=1;i<n;i++){
		int temp = arr[i];
		int j;
		for(j=i;j>0 && arr[j-1] > temp;j--){
			arr[j] = arr[j-1];
		}
		arr[j] = temp;
	}
}

迄今为止,学了三种基础排序,插入排序可以进行优化。
冒泡排序最慢、选择排序次之、插入排序再次之。(在一个基本有序的数列中,插入排序的速度有时比O(NlogN)的排序算法还快。

归并排序

void mergeSort(int* arr,int n);
void process(int* arr,int L,int R);
void merge(int* arr,int L,int mid,int R);

void mergeSort(int* arr,int n){
	process(arr,0,n-1);
}

void process(int* arr,int L,int R){
	if(L >= R){
		return;
	}
	int mid = L + ((R-L)>>1);
	process(arr,L,mid);
	process(arr,mid+1,R);
	merge(arr,L,mid,R);
}

void merge(int* arr,int L,int mid,int R){
	int size = R-L+1;
	新建数组
	int* temp = (int*)malloc(sizeof(int)*size);
	int p1 = L;
	int p2 = mid+1;
	int i = 0;
	while(p1 <= L && p2 <= R){
		temp[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
	}
	while(p1 <= mid){
		temp[i++] = arr[p1++];
	}
	while(p2 <= R){
		temp[i++] = arr[p2++];
	}
	for(i=0;i<size;i++){
		arr[L+i] = temp[i];
	}
}

快速排序

// 快速排序
int partition(int* arr, int L, int R);
void quick(int* arr, int L, int R);
void quickSort(int* arr,int n);

void quickSort(int* arr, int n) { 
	quick(arr, 0, n - 1); 
	return;
}

int partition(int* arr, int L, int R) {
    // 设置基准
    int temp = arr[L];
    int front = L;
    
    for (int rear = L + 1; rear <= R; rear++) {
        if (arr[rear] < temp) {
            swap(arr, rear, ++front);
        }
    }
    swap(arr, L, front);
    return front;
}

void quick(int* arr, int L, int R) {
    if (L >= R) {
        return;
    }
    int p = partition(arr, L, R);
    quick(arr, L, p - 1);
    quick(arr, p + 1, R);
}

小结:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define N 5000000

void swap(int* arr, int i, int j) {
    int temp = *(arr + i);
    *(arr + i) = *(arr + j);
    *(arr + j) = temp;
}

// 快速排序

int partition(int* arr, int L, int R);
void quick(int* arr, int L, int R);

void quickSort(int* arr, int n) { quick(arr, 0, n - 1); }

int partition(int* arr, int L, int R) {
    // 设置基准
    int temp = arr[L];

    int front = L;

    for (int rear = L + 1; rear <= R; rear++) {
        if (arr[rear] < temp) {
            swap(arr, rear, ++front);
        }
    }
    swap(arr, L, front);
    return front;
}

void quick(int* arr, int L, int R) {
    if (L >= R) {
        return;
    }
    int p = partition(arr, L, R);
    quick(arr, L, p - 1);
    quick(arr, p + 1, R);
}

// 交换
void insertSort(int* arr, int n) {
    for (int i = 1; i < n; i++) {
        for (int j = i; j > 0; j--) {
            if (arr[j] < arr[j - 1]) {
                swap(arr, j, j - 1);
            }
        }
    }
}

// 赋值代替交换
void insertSortPro(int* arr, int n) {
    for (int i = 1; i < n; i++) {
        int e = arr[i];  // 临时保存
        int j;           // 保存元素e应该插入的位置
        for (j = i; j > 0 && arr[j - 1] > e; j--) {
            arr[j] = arr[j - 1];
        }
        arr[j] = e;
    }
}

// 选择排序
void selectionSort(int* arr, int n) {
    for (int i = 0; i < n; i++) {
        int minIndex = i;
        for (int j = 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        swap(arr, i, minIndex);
    }
}

// 冒泡排序
void bubbleSort(int* arr, int n) {
    for (int i = n - 1; i > 0; i--) {
        for (int j = 0; j < i; j++) {
            if (arr[j] > arr[j + 1]) {
                swap(arr, j, j + 1);
            }
        }
    }
}

// 复制数组
int* copyIntArray(int* arr, int n) {
    int* newArr = (int*)malloc(sizeof(int) * n);
    for (int i = 0; i < n; i++) {
        *(newArr + i) = *(arr + i);
    }
    return newArr;
}

// 打印数组
void print(int* arr, int n) {
    for (int i = 0; i < n; i++) {
        if (i % 10 == 0) {
            printf("\n");
        }
        printf("%d\t", *(arr + i));
    }
    printf("\n");
}

// 按照长度和范围随机构建数组
int* getArr(int size, int randL, int randR) {
    srand((unsigned)time(NULL));
    int* arr = (int*)malloc(sizeof(int) * size);
    for (int i = 0; i < size; i++) {
        *(arr + i) = rand() % (randR - randL + 1) + randL;
    }
    return arr;
}

void merge(int* arr, int L, int mid, int R);
void process(int* arr, int L, int R);

void mergeSort(int* arr, int n) {
    process(arr, 0, n - 1);
    return;
}

void process(int* arr, int L, int R) {
    if (L >= R) {
        return;
    }
    int mid = L + ((R - L) >> 1);
    process(arr, L, mid);
    process(arr, mid + 1, R);
    merge(arr, L, mid, R);
}

void merge(int* arr, int L, int mid, int R) {
    // 创建一个 (R-L+1) 长度的数组
    int size = R - L + 1;
    int* newArr = (int*)malloc(sizeof(int) * size);

    for (int i = L; i <= R; i++) {
        newArr[i - L] = arr[i];
    }

    // 开始排序
    int front = L;
    int rear = mid + 1;
    int i = 0;
    while (front <= mid && rear <= R) {
        newArr[i++] = arr[front] < arr[rear] ? arr[front++] : arr[rear++];
    }
    while (front <= mid) {
        newArr[i++] = arr[front++];
    }
    while (rear <= R) {
        newArr[i++] = arr[rear++];
    }
    for (i = 0; i < size; i++) {
        arr[i + L] = newArr[i];
    }
}

int* generateNearlyOrderedArray(int n, int count) {
    srand((unsigned)time(NULL));
    int* arr = (int*)malloc(sizeof(int) * n);
    for (int i = 0; i < n; i++) {
        arr[i] = i + 1;
    }
    for (int j = 0; j < count; j++) {
        int p1 = rand() % n;
        int p2 = rand() % n;
        swap(arr, p1, p2);
    }
    return arr;
}

void test01() {
    clock_t begin;
    clock_t end;
    double time;
    int* arr1 = getArr(N, 0, N);
    int* arr2 = copyIntArray(arr1, N);
    int* arr3 = copyIntArray(arr1, N);
    int* arr4 = copyIntArray(arr1, N);
    int* arr5 = copyIntArray(arr1, N);

    // 计算归并排序时间
    printf("\n");
    begin = clock();
    mergeSort(arr5, N);
    end = clock();
    time = end - begin;
    time = time / CLOCKS_PER_SEC;
    printf("mergeSort:\t%10lf s\n", time);

    // 计算插入排序(落后)时间

    begin = clock();
    insertSort(arr1, N);
    end = clock();
    time = end - begin;
    time = time / CLOCKS_PER_SEC;
    printf("insertSort:\t%10lf s\n", time);

    // 计算插入排序(改进)时间
    begin = clock();
    insertSortPro(arr2, N);
    end = clock();
    time = end - begin;
    time = time / CLOCKS_PER_SEC;
    printf("insertSortPro:\t%10lf s\n", time);

    // 计算选择排序时间
    begin = clock();
    selectionSort(arr3, N);
    end = clock();
    time = end - begin;
    time = time / CLOCKS_PER_SEC;
    printf("selectionSort:\t%10lf s\n", time);

    // 计算冒泡排序时间
    begin = clock();
    bubbleSort(arr4, N);
    end = clock();
    time = end - begin;
    time = time / CLOCKS_PER_SEC;
    printf("bubbleSort:\t%10lf s\n", time);

    printf("\n");

    free(arr1);
    free(arr2);
    free(arr3);
    free(arr4);
    free(arr5);
    arr1 = NULL;
    arr2 = NULL;
    arr3 = NULL;
    arr4 = NULL;
    arr5 = NULL;
}

void test02() {
    clock_t begin;
    clock_t end;
    double time;
    int* arr1 = generateNearlyOrderedArray(N, 2);
    int* arr2 = copyIntArray(arr1, N);
    int* arr3 = copyIntArray(arr1, N);
    int* arr4 = copyIntArray(arr1, N);
    int* arr5 = copyIntArray(arr1, N);

    // 计算归并排序时间
    printf("\n");
    begin = clock();
    mergeSort(arr5, N);
    end = clock();
    time = end - begin;
    time = time / CLOCKS_PER_SEC;
    printf("mergeSort:\t%10lf s\n", time);

    // 计算插入排序(落后)时间

    begin = clock();
    insertSort(arr1, N);
    end = clock();
    time = end - begin;
    time = time / CLOCKS_PER_SEC;
    printf("insertSort:\t%10lf s\n", time);

    // 计算插入排序(改进)时间
    begin = clock();
    insertSortPro(arr2, N);
    end = clock();
    time = end - begin;
    time = time / CLOCKS_PER_SEC;
    printf("insertSortPro:\t%10lf s\n", time);

    // 计算选择排序时间
    begin = clock();
    selectionSort(arr3, N);
    end = clock();
    time = end - begin;
    time = time / CLOCKS_PER_SEC;
    printf("selectionSort:\t%10lf s\n", time);

    // 计算冒泡排序时间
    begin = clock();
    bubbleSort(arr4, N);
    end = clock();
    time = end - begin;
    time = time / CLOCKS_PER_SEC;
    printf("bubbleSort:\t%10lf s\n", time);

    printf("\n");

    free(arr1);
    free(arr2);
    free(arr3);
    free(arr4);
    free(arr5);
    arr1 = NULL;
    arr2 = NULL;
    arr3 = NULL;
    arr4 = NULL;
    arr5 = NULL;
}

int main() {
    clock_t begin;
    clock_t end;
    double time;
    int* arr1 = getArr(N, 0, N);
    int* arr2 = copyIntArray(arr1, N);

    // 计算归并排序时间
    printf("\n");
    begin = clock();
    mergeSort(arr1, N);
    end = clock();
    time = end - begin;
    time = time / CLOCKS_PER_SEC;
    printf("mergeSort:\t%10lf s\n", time);

    // 计算快速排序时间
    begin = clock();
    quickSort(arr2, N);
    end = clock();
    time = end - begin;
    time = time / CLOCKS_PER_SEC;
    printf("quickSort:\t%10lf s\n", time);
    printf("\n");

    free(arr1);
    free(arr2);

    arr1 = NULL;
    arr2 = NULL;
}

总结

快速排序大部分情况比归并排序还要快,在数组基本有序的情况下,优化过的插入排序比归并排序都要快。基础排序冒泡、选择都是非常慢的,O(N^2)级别的时间复杂度。
快速排序和归并排序是O(N logN)级别的。

posted @ 2023-08-28 15:59  zxinlog  阅读(14)  评论(0)    收藏  举报