zoukankan      html  css  js  c++  java
  • 三种排序:快排,归并,堆排

    转自:http://www.cnblogs.com/LUO77/p/5798149.html

    (一)快排

    快排考的是最多次的。之前看大神写的算法很简单,思想也很好。就一直用他的思想去思考快排了。挖坑法。

    拿走第一个元素作为标兵元素,即挖坑,然后从后面找一个比它小的填坑,然后又形成一个坑,再从前面找一个比标兵大的填坑,又形成一个坑。……最后一个坑填入标兵就好。

    然后就是递归了。再在标兵左边排序,右边排序。

     1 void QSort(int* num, int start, int end) {
     2     if(num == NULL||start >= end)
     3         return;
     4     int tmp = num[start];
     5     int i = start, j = end;
     6     while (i<j) {
     7         while (i<j&&num[j]>tmp) {
     8             j--;
     9         }
    10         if (i<j)
    11             num[i++] = num[j];
    12         while (i<j&&num[i]<tmp) {
    13             i++;
    14         }
    15         if (i<j)
    16             num[j--] = num[i];
    17     }
    18     num[i] = tmp;
    19     QSort(num, start, i - 1);
    20     QSort(num, i + 1, end);
    21 }

    归并:

    归并的思想就是分治-组合。

    先divide,然后merge。

    divide的思想比较简单,找到middle,再划分A[start,,,,,middle],A[middle+1...end]

    对于左边在递归划分,划分直至只剩一个元素,然后再merge。merge的时候需要一个临时数组。merge的时候是A[first...middle]和A[middle+1……end]合并。

    对于右边在递归划分,划分直至只剩一个元素,然后再merge。

    左边和右边都有序了,然后再将两个数组合并为一个数组。最后整个数组都有序了。(先处理左边,再处理右边)

     1 void merge(int* A, int start, int middle, int last, int *tmp) {
     2 
     3     int i1 = start, j1 = middle;
     4     int i2 = middle+1, j2 = last;
     5     int index = 0;
     6     while (i1<=j1&&i2<=j2) {
     7         if (A[i1]<=A[i2])
     8             tmp[index++] = A[i1++];
     9         else tmp[index++] = A[i2++];
    10     }
    11     while (i1 <= j1) {
    12         tmp[index++] = A[i1++];
    13     }
    14     while (i2 <= j2) {
    15         tmp[index++] = A[i2++];
    16     }
    17     for (int i = 0; i<index; i++) {
    18         A[start + i] = tmp[i];
    19     }
    20     return;
    21 }
    22 void divide(int* A, int start, int end, int* tmp) {
    23     if (start<end) {
    24         int middle = (start + end) / 2;
    25         divide(A, start, middle, tmp);
    26         divide(A, middle+1, end, tmp);
    27         merge(A, start, middle, end, tmp);
    28     }
    29 }
    30 void mergesort(int* A, int size) {
    31     if (A == NULL || size == 0 || size == 1)
    32         return;
    33     int* tmp = new int[size];
    34     divide(A, 0, size - 1, tmp);
    35     delete[] tmp;
    36     return;
    37 }

    堆排序(以最大堆为例子):
    1.首先要构建一个最大堆(从size/2-1位置开始维护堆,叶子节点默认已经是一个最大堆了,维护到根节点,则已经构成一个最大堆)
    2.交换根节点(此时根节点是最大值),和最后一个节点,破坏了最大堆的性质,此时继续维护最大堆(维护最大堆的过程就是类似直接插入排序,找到维护点合适插入的位置,保证最大堆性质不被破坏就好)
    3.循环交换最后一个节点和根节点,每次维护最大堆的规模减一(找到最大,找到次大,次次大……),到最后到根节点,也就排序完成了。

     1 void swap(int& a, int& b) {
     2     a ^= b;
     3     b ^= a;
     4     a ^= b;
     5 }
     6 void HeapAdjust(int* A, int size, int start) {
     7     int i = start;
     8     int j = 2 * i + 1;
     9     int tmp = A[i];
    10     while (j <= size) {
    11         if (j + 1 <= size&&A[j + 1]>A[j])
    12             j++;
    13         if (A[j] <= tmp)
    14             break;
    15         A[i] = A[j];
    16         i = j;
    17         j = 2 * i + 1;
    18     }
    19     A[i] = tmp;
    20     return;
    21 }
    22 
    23 void CreateHeap(int* A, int size) {
    24     for (int i = size / 2 - 1; i >= 0; i--)
    25         HeapAdjust(A, size - 1, i);
    26 }
    27 
    28 void HeapSort(int* A, int size) {
    29     if (A == NULL || size == 0 || size == 1)
    30         return;
    31     CreateHeap(A, size);
    32     for (int i = size - 1; i >= 1;) {
    33         swap(A[0], A[i--]);
    34         HeapAdjust(A, i, 0);
    35     }
    36 }
  • 相关阅读:
    修改Ubuntu从文本界面登录
    Putty等工具中解决SSH连接超时断开的问题
    QoS policy-map class-map
    Linux中的do{...} while(0)
    手动增加swap分区
    __attribute__ 机制详解(一)
    欢迎来语雀关注我
    WebForm 生成并显示二维码
    《C#图解教程》 总览
    C#图解教程 第二十五章 其他主题
  • 原文地址:https://www.cnblogs.com/demian/p/8206734.html
Copyright © 2011-2022 走看看