排序

Posted sanweizuiji

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序相关的知识,希望对你有一定的参考价值。

1 排序

1.1 内排序、外排序

1.2 排序的稳定性

2 排序算法

#include <stdio.h>

// 共 46 个元素
#define arrSize 46
// 辅助数组,用来将 arr 复制一份保存到 tempArr 中
int tempArr[arrSize] = 0;

int main() 
    int arr[] = 123, 234, 3546, 1, 3, 5, 767, 8, 9, 78, 1,
                 214, 5, 6, 457, 8, 8, 5, 5, 2124, 5,
                 656688, 4, 4, 6, 541, 24, 412, 5, 6454, 68,
                 8, 979, 780870, 231, 1, 2, 4, 4, 54647, 56,
                 35, 23, 52, 3, 37;
    // insertionSort(arr, arrSize);
    // shellSort(arr, arrSize);
    // bubbleSort(arr, arrSize);
    // quickSort(arr, 0, arrSize);
    // selectSort(arr, arrSize);
    // heapSort(arr, arrSize - 1);
    // mergeSort(arr, 0, arrSize - 1);
    for (int i = 0; i < arrSize; i++) 
        printf("%d\\n", arr[i]);
    

2.1 直接插入排序

void insertionSort(int arr[], int size) 
    for (int i = 1; i < size; i++) 
        if (arr[i] < arr[i - 1]) 
            int temp = arr[i];
            // 检查所有前面已排好序的元素,将比 temp 大的元素后移,并将 temp 插入到合适位置
            int j;
            for (j = i - 1; j >= 0 && temp < arr[j]; j--) 
                arr[j + 1] = arr[j];
            
            arr[j + 1] = temp;
        
    

空间复杂度
O ( 1 ) O(1) O(1)
时间复杂度(主要来自对比关键字、移动元素)
最好情况(原本就有序):共n-1趟处理,每一趟只需要对比关键字1次,不用移动元素
O ( n ) O(n) O(n)
最坏情况(原本为逆序):第 1 趟:对比关键字2次,移动元素3次;第 2 趟:对比关键字3次,移动元素4次;第 i 趟:对比关键字i+1次,移动元素i+2次
O ( n 2 ) O(n^2) O(n2)
平均时间复杂度
O ( n 2 ) O(n^2) O(n2)

例 (插入排序)在链表中进行操作比在顺序表中进行操作效率高

2.2 Shell 排序(不稳定,划分子表后排序可能导致不稳定)

void shellSort(int arr[], int size) 
    // 步长初始化为数组长度的一半,每次遍历后步长减半
    for (int gap = size / 2; gap > 0; gap /= 2) 
        // 变量 i 为每次分组的第一个元素下标
        for (int i = 0; i < gap; i++) 
            // 对步长为 gap 的元素组进行直接插入排序
            for (int j = i + gap; j < size; j = j + gap) 
                if (arr[j] < arr[j - gap]) 
                    int temp = arr[j];
                    // 检查所有前面已排好序的元素
                    int k;
                    for (k = j - gap; k >= 0 && temp < arr[k]; k = k - gap) 
                        arr[k + gap] = arr[k];
                    
                    arr[k + gap] = temp;
                
            
        
    

空间复杂度
O ( 1 ) O(1) O(1)
时间复杂度

2.3 冒泡排序

void bubbleSort(int arr[], int size) 
    // 每趟都把最小的数移到最前面
    for (int i = 0; i < size - 1; i++) 
        int flag = 0;
        for (int j = size - 1; j > i; j--) 
            if (arr[j] < arr[j - 1]) 
                int temp = arr[j - 1];
                arr[j - 1] = arr[j];
                arr[j] = temp;
                flag = 1;
            
        
        // 若这趟没有发生交换,说明剩余序列已经有序了
        if (flag == 0) 
            break;
        
    

空间复杂度
O ( 1 ) O(1) O(1)
时间复杂度
最好情况(原本有序):比较次数 n-1 次,flag 表明没有发生交换操作
O ( n ) O(n) O(n)
最坏情况(原本逆序):
O ( n 2 ) O(n^2) O(n2)
平均时间复杂度:
O ( n 2 ) O(n^2) O(n2)

2.4 快速排序(不稳定,如对 2 2 1 进行排序,第一个 2 作为基准元素时会被移动到第三个位置)

// 用第一个元素将待排序的序列划分成左右两个部分
int partition(int arr[], int low, int high) 
    // 第一个元素作为基准
    int pivot = arr[low];
    // 用 low 和 high 搜索基准最终位置
    while (low < high) 
        // high 一直左移,直到找到比基准小的数后停止循环
        while (low < high && arr[high] >= pivot) 
            high--;
        
        // 将找到的比基准小的数移动到左边
        arr[low] = arr[high];
        // low 一直右移,直到找到比基准大的数后停止循环
        while (low < high && arr[low] <= pivot) 
            low++;
        
        // 将找到的比基准大的数移动到右边
        arr[high] = arr[low];
    
    arr[low] = pivot;
    // 返回基准元素存放的位置
    return low;


void quickSort(int arr[], int low, int high) 
    if (low < high) 
        int pivotPos = partition(arr, low, high);
        quickSort(arr, low, pivotPos - 1);
        quickSort(arr, pivotPos + 1, high);
    

空间复杂度(递归层数 = 用基准元素划分生成的二叉树的深度)
最好情况:
O ( l o g 2 n ) O(log_2n) O(log2n)
最坏情况:
O ( n ) O(n) O(n)
时间复杂度
最好情况:
O ( n ∗ 递归层数 ) = O ( n ∗ l o g 2 n ) O(n*递归层数)=O(n*log_2n) O(n递归层数)=O(nlog2n)
最坏情况:
O ( n ∗ 递归层数 ) = O ( n ∗ n ) = O ( n 2 ) O(n*递归层数)=O(n*n)=O(n^2) O(n递归层数)=O(nn)=O(n2)
平均:
O ( n ∗ 递归层数 ) = O ( n ∗ l o g 2 n ) O(n*递归层数)=O(n*log_2n) O(n递归层数)=O(nlog2n)

2.5 简单选择排序(不稳定,如对 2 2 1 进行排序)

void selectSort(int arr[], int arrSize) 
    for (int i = 0; i < arrSize - 1; i++) 
        // 记录最小元素的位置
        int min = i;
        // 在i+1-n中选择最小的元素
        for (int j = i + 1; j < arrSize; j++) 
            if (arr[j] < arr[min]) 
                // 更新最小元素位置
                min = j;
            
        
        // 如果发现更小的元素则与 arr[i] 交换
        if (min != i) 
            int temp = arr[i];
            arr[i] = arr[min];
            arr[min] = temp;
        
    

空间复杂度
O ( 1 ) O(1) O(1)
时间复杂度
O ( n 2 ) O(n^2) O(n2)

2.6 堆排序(不稳定,如对 1 2 2 进行排序)

// fallingElement 为需要下坠的元素
void headAdjust(int arr[], int fallingElement, int len) 
    // arr[0] 保存本次要下坠的元素
    arr[0] = arr[fallingElement];
    for (int j = fallingElement * 2; j <= len; j = j * 2) 
        // 判断左右孩子的大小,调整 j
        if (j < len && arr[j] < arr[j + 1]) 
            j = j + 1;
        
        // 如果本次下坠的元素大于左右孩子,那符合大根堆的要求,直接跳出下坠操作,如果不满足,则将较大的孩子结点移动到目前下坠元素的位置
        if (arr[0] >= arr[j]) 
            break;
         else 
            arr[fallingElement] = arr[j];
            fallingElement = j;
        
    
    arr[fallingElement] = arr[0];


// 建立大根堆
void buildMaxHeap(int arr[], int len) 
    for (int i = len / 2; i > 0; i--) 
        headAdjust(arr, i, len);
    


// 堆排序(注意用 a[0] 是用来暂存元素的,len 是除 a[0] 以外的数组元素的个数)
void heapSort(int arr[], int len) 
    buildMaxHeap(arr, len);
    for (int i = len; i > 1; i--) 
        // 交换已经构建好的大根堆的首尾元素
        int temp = arr[i];
        arr[i] = arr[1];
        arr[1] = temp;
        // 再将第一个元素下坠,并且最后一个元素已确定位置,故不在考虑范围之内
        headAdjust(arr, 1, i - 1);
    

空间复杂度
O ( 1 ) O(1) O(1)
时间复杂度
O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

例 堆排序是一种(选择)排序

2.7 归并排序

// arr[low,mid] 和 arr[mid+1,high] 各自有序,将两个部分归并
void merge(int arr[], int low, int mid, int high) 
    // 将 arr 中所有元素复制到 tempArr 中
    for (int i = low; i <= high; i++) 
        tempArr[i] = arr[i];
    
    int temp_i, temp_j, arr_k;
    for (temp_i = low, temp_j = mid + 1, arr_k = low; temp_i <= mid && temp_j <= high; arr_k++) 
        if (tempArr[temp_i] <= tempArr[temp_j]) 
            arr[arr_k] = tempArr[temp_i];
            temp_i = temp_i + 1;
         else 
            arr[arr_k] = tempArr[temp_j];
            temp_j = temp_j + 1;
        
    
    // 将剩余的元素也赋值到 arr 中
    while (temp_i <= mid) 
        arr[arr_k] = tempArr[temp_i];
        arr_k = arr_k + 1;
        temp_i = temp_i + 1;
    
    while (temp_j <&#

以上是关于排序的主要内容,如果未能解决你的问题,请参考以下文章

冒泡排序===快速排序

一看就懂的快速排序

一看就懂的快速排序

快速排序

排序之快速排序

PHP 快速排序