• HDU-1425-sort(计数排序以及快速排序和堆排序的变种)


    • 计数排序
      Accepted 1425 483MS 5276K 997 B G++
      #include "bits/stdc++.h"
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      const int INF = 0x3f3f3f3f;
      const int MAXN = 1e6 + 5;
      const int MIN_NUM = -5e5;
      const int MAX_NUM = 5e5;
      // MAX_NUM - MIN_NUM 表示输入数字的范围
      int num[MAX_NUM - MIN_NUM + 10];
      int main() {
          int n, m, k;
          while (~scanf("%d%d", &n, &m)) {
              while (n--) {
                  scanf("%d", &k);
                  // 因为存在负数而没有负下标,所以将所有输入的数减去MIN_NUM然后再存入对应下标
                  num[k - MIN_NUM]++;
              }
              k = MAX_NUM - MIN_NUM;
              while (m--) {
                  while (num[k] == 0) {
                      k--;
                  }
                  num[k]--;
                  if (m != 0) {
                      printf("%d ", k + MIN_NUM);
                  } else {
                      printf("%d
      ", k + MIN_NUM);
                  }
              }
              // k后面的都已经清空了所以,这里只要清空k前面这段就好了;
              memset(num, 0, sizeof(int) * (k + 1));
          }
          return 0;
      }

      计数排序适用于排序范围已知且排序数量大,排序范围小的情况。复杂度为Ο(n+k)。n表示排序数量,k表示排序范围;计数排序还有个优点在于不用记录原数,所有只要排序范围比较小是比较省空间的;

    • 堆排序变种
      Accepted 1425 499MS 2156K 1290 B G++
      #include "bits/stdc++.h"
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      const int INF = 0x3f3f3f3f;
      const int MAXN = 1e6 + 5;
      int arr[MAXN];
      int n, m, k;
      void minHeapFix (int id) {
          int mn = id << 1;
          if (mn > m) {
              return;
          }
          if (mn < m && arr[mn | 1] < arr[mn]) {
              mn |= 1;
          }
          if (arr[mn] < arr[id]) {
              swap(arr[mn], arr[id]);
              minHeapFix(mn);
          }
      }
      int main() {
          while (~scanf("%d%d", &n, &m)) {
              // 因为题目要求前m大,所以这里的堆只维护前m大的数
              for (int i = 1; i <= m; i++) {
                  scanf("%d", &arr[i]);
              }
              for (int i = m >> 1; i; i--) {
                  minHeapFix(i);
              }
              for (int i = m + 1; i <= n; i++) {
                  scanf("%d", &k);
                  // 这里维护的是小顶堆,堆顶最小,如果k比前m大中最小的数要大,用k替换堆顶,再维护小顶堆
                  if (k > arr[1]) {
                      arr[1] = k;
                      minHeapFix(1);
                  }
              }
              k = m;
              for (int i = 1; i < k; i++) {
                  swap(arr[1], arr[m--]);
                  minHeapFix(1);
              }
              for (int i = 1; i < k; i++) {
                  printf("%d ", arr[i]);
              }
              printf("%d
      ", arr[k]);
          }
          return 0;
      }

      这题用堆排好在于他不用维护n个数只要维护前m大的数就够了,但是题目中说(0<n,m<1000000)可见m也不小了,所以比计排还要慢些,如果m比较小还是很快的。

    • 快速排序变种
      Accepted 1425 468MS 3332K 1460 B G++
      #include "bits/stdc++.h"
      using namespace std;
      typedef long long LL;
      const int INF = 0x3f3f3f3f;
      const int MAXN = 1e6 + 5;
      int arr[MAXN];
      int n, m;
      void quickSort(int l, int r) {
          if (l >= r) {
              return;
          }
          int mid = l + r >> 1, id;
          if (arr[l] <= arr[mid] && arr[l] <= arr[r]) {
              id = arr[mid] <= arr[r] ? mid : r;
          } else {
              if (arr[mid] <= arr[r]) {
                  id = arr[l] <= arr[r] ? l : r;
              } else {
                  id = arr[l] <= arr[mid] ? l : mid;
              }
          }
          swap(arr[l], arr[id]);
          int ge = l + 1, lt = r;
          while (ge < lt) {
              if (arr[ge] >= arr[l]) {
                  ge++;
              } else if (arr[lt] >= arr[l]){
                  swap(arr[ge], arr[lt]);
                  ge++;
                  lt--;
              } else {
                  while (arr[lt] < arr[l] && ge < lt) {
                      lt--;
                  }
              }
          }
          if (arr[ge] < arr[l]) {
              ge--;
          }
          swap(arr[ge], arr[l]);
          quickSort(l, ge - 1);
          // 变种就变在这个if, 因为只要前m大的数有序,所以当ge >= m时就不用排后面的数了
          if (ge < m) {
              quickSort(ge + 1, r);
          }
      }
      int main() {
          while (~scanf("%d%d", &n, &m)) {
              for (int i = 1; i <= n; i++) {
                  scanf("%d", &arr[i]);
              }
              quickSort(1, n);
              for (int i = 1; i < m; i++) {
                  printf("%d ", arr[i]);
              }
              printf("%d
      ", arr[m]);
          }
          return 0;
      }
    • 快速排序再变种
      Accepted 1425 468MS 3332K 1264 B G++
      #include "bits/stdc++.h"
      using namespace std;
      typedef long long LL;
      const int INF = 0x3f3f3f3f;
      const int MAXN = 1e6 + 5;
      int arr[MAXN];
      int n, m;
      void quickSort(int l, int r, int mn, int mx) {
          if (l >= r || mn >= mx) {
              return;
          }
          // 取排序范围的中值作为mid
          int mid = mn + mx >> 1;
          /* 
          下面的if很重要,原先没加导致
          5 5
          1 2 3 4 5
          这组数据死循环。
          */
          if (mid == mn) {
              mid++;
          }
          int ge = l, lt = r;
          while (ge < lt) {
              if (arr[ge] >= mid) {
                  ge++;
              } else if (arr[lt] >= mid){
                  swap(arr[ge], arr[lt]);
                  ge++;
                  lt--;
              } else {
                  while (arr[lt] < mid && ge < lt) {
                      lt--;
                  }
              }
          }
          if (arr[ge] < mid) {
              ge--;
          }
          quickSort(l, ge, mid, mx);
          if (ge < m) {
              quickSort(ge + 1, r, mn, mid - 1);
          }
      }
      int main() {
          while (~scanf("%d%d", &n, &m)) {
              for (int i = 1; i <= n; i++) {
                  scanf("%d", &arr[i]);
              }
              quickSort(1, n, -5e5, 5e5);
              for (int i = 1; i < m; i++) {
                  printf("%d ", arr[i]);
              }
              printf("%d
      ", arr[m]);
          }
          return 0;
      }

      一般的快排都会采用三点取中法来找mid,但是这个mid并不是数组真正的中位数,所以这里采用数据范围的中值作为mid。本来以为会快一点的,但是好像和上面的快排差不多,看样子三点取中法还是很靠谱的。另外写二分一定注意死循环,快被二分死循环搞疯了。

  • 相关阅读:
    things to analysis
    retrieve jenkins console output
    temp
    temp
    mysql on Mac OS
    Scala的几个小tips
    docker查看容器使用率
    JVM性能监控(jconsole和jvisualvm)
    线程死锁问题
    线程阻塞状态
  • 原文地址:https://www.cnblogs.com/Angel-Demon/p/10297768.html
Copyright © 2020-2023  润新知