排序算法

 

 

简单排序

冒泡排序

冒泡排序,类似于水中冒泡,较大的数沉下去,较小的数慢慢冒起来,假设从小到大,即为较大的数慢慢往后排,较小的数慢慢往前排。

直观表达,每一趟遍历,将一个最大的数移到序列末尾。

void bubbleSort(int* array, int len) {
    for (int n = 0; n < len - 1; n++) {
        for (int m = 0; m < len - 1 - n; m++) {
            if (array[m] > array[m + 1]) {
                int tmp = array[m];
                array[m] = array[m + 1];
                array[m + 1] = tmp;
            }
        }
    }
}

 

 

 

选择排序

每一次遍历待排序的序列,记录最小值的下标,和待排序第一个元素进行比较,如果小与待排序第一个元素,交换

void selectSort(vector<int>& arr) {
    for (int i = 0, k = 0; i < arr.size(); i++, k = i){
        // 这一层查找后面最小值的下标
        for (int j = i + 1; j < arr.size(); j++) {
            if (arr[k] > arr[j]) {
                k = j;
            }
        }
        // 交换值
        if (i != k) {
            int temp = arr[i];
            arr[i] = arr[k];
            arr[k] = temp;
        }
    }
}

 

 

 

插入排序

插入的意思是指将一个元素插入一个已排序序列中,选择好插入位置后,需要将插入位置以后的元素依次往后移动一个位置。

void InsertionSort(int *array, int N)
{
      int j, k, key;
      for (j=1; j<N; j++) {
            key = array[j];
            for (k=j-1; k>=0 && key<array[k]; k--) {
                   array[k+1] = array[k]; 
             } 
             array[k+1] = key;
      } 
}

 

 

快速排序

在待排序序列中选择一个支点,以该支点为界,序列中比它小的元素放到它前面,比它大的元素放到它后面。

int partition(int *array, int p, int r)
{
    int key = array[r];
    int i = p; 
    int j;
    for (j=p; j<r; j++) {
        if (array[j] <= key)
            swap(&array[i++], &array[j]);
    }  
    swap(&array[i], &array[r]);
    return i;
}

void QSort(int *array, int p, int r)
{
    int q;
    if (p < r) {
        q = partition(array, p, r);
        QSort(array, p, q-1);
        QSort(array, q+1, r);
    }  
}

 

 

 

 

归并排序

采用分治算法, 

void merge(int* array, int p, int mid, int r) {
    vector<int> aux(r - p + 1);
    for (int k = p; k <= r; k++) {
        aux[k] = array[k];
    }

    int i = p;          // left: [p, mid]
    int j = mid + 1;    // right: [mid + 1, r]
    for (int k = p; k <= r; k++) {
        if (i > mid) array[k] = aux[j++];
        else if (j > r) array[k] = aux[i++];
        else if (aux[j] < aux[i]) array[k] = aux[j++];
        else array[k] = aux[i++];
    }
}

void mergeSort(int* array, int p, int r) {
    if (p >= r) return;
    int mid = (p + r) / 2;

    mergeSort(array, p, mid);
    mergeSort(array, mid + 1, r);
    merge(array, p, mid, r);
}

 

 

 

堆排序

参考这里

 

 

计数排序

假设输入数组A[1,...,n]中的每一个元素都满足 0<=A[i]<=k,可以借助一个辅助的k维数组C[0,...,k]来对数组A排序,并将排序后的结果输出到数组B;
 
实现步骤:
1、找出待排序数组A中的最大和最小的元素;
2、统计数组A中每个值为i的元素出现的次数,存入数组C的第i项;
3、对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
4、反向填充目标数组B,将每个元素i放在B[C[i]],每放一个元素就将C[i]减1;

 

void CountingSort(int *A, int *B, int N) {
     int n = 0;
     const int K = 1 + max(A, N);
     int C[K];
     for (n=0; n<K; n++)
          C[n] = 0;
    
     for (n=0; n<N; n++)
          C[A[n]]++;

     for (n=1; n<K; n++)
          C[n] += C[n-1];

     for (n=N-1; n>=0; n--) {
          B[C[A[n]] - 1] = A[n];
          C[A[n]]--;
     }

}

 

 

 

 

桶排序

桶排序是将数组分到有限数量的桶子里,每个桶里面再分别排序。
当待排序数组内的数值服从均匀分布的时候,桶排序使用线性时间O(n)。
 
 
 
 

基数排序

思路:
1、将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零;
2、从低位开始,依次进行一次排序,这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
 
 
 
 
 

希尔排序

 

 

 

总结

 
(1) 上表中的简单排序包括除希尔排序之外的所有插入排序、冒泡排序和选择排序,其中以直接插入排序为最简单,当序列中的记录“基本有序”或 n值较小时,它是最佳排序方法。
(2) 从平均时间性能而言,快速排序最佳,其所需时间最省,但快速排序在最坏情况下的时间性能不如堆排序和归并排序。而后两者相比的结果是,在 n较大时,归并排序所需时间较堆排序省,但它所需的辅助存储量最多。
(3) 基数排序适用于n值很大而关键字较小的序列。若关键字也很大,而序列中大多数记录的“最高位关键字”均不同,则亦可先按“最高位关键字”不同将序列分成若干“小”的子序列,而后进行直接插入排序。
(4) 从方法的稳定性来比较,所有时间复杂度为 O(n^2)的简单排序法也是稳定的,然而,快速排序、堆排序和希尔排序等时间性能较好的排序方法都是不稳定的。
  
 

 

 

 

topK

问题描述:在数组A[p,...,r]中找到第k小的元素key,显然0<=k<=(r-p+1);
 
思路:可以借鉴快速排序的分治算法,如下
1、将A[p,...,r]划分成两个子数组A[p,...,q-1]和A[q+1,...,r];
2、然后判断第k小的元素key位于哪个子数组中;
3、如果k==(q-p+1),则返回key=A[q];
4、如果key位于第一个子数组,则继续在A[p,...,q-1]中求第k小的元素;
5、如果key位于第二个子数组,则在A[q+1,...,r]中求第(k-(q-p+1))小的元素;

int partition(int *array, int p, int r) {
    int key = array[r];
    int i, j = p;
    for (i = p; i < r; i++) {
        if (array[i] <= key) {
            swap(&array[j++], &array[i]);
        }
    }
    swap(&array[j], &array[r]);
    return j;
}

int topk(int *array, int p, int r, int k) {
    if (p == r) return array[p];

    int q = partition(array, p, r);

    if (p + k - 1 == q) {
        return array[q];
    } else if (p + k - 1 > q) {
        return topk(array, q + 1, r, k - (q - p + 1));
    } else {
        return topk(array, p, q - 1, k);
    }
}

 

 

 

 

 

posted @ 2020-12-20 16:44  如果的事  阅读(115)  评论(0编辑  收藏  举报