当前位置:   article > 正文

快速排序与归并排序的非递归算法_为实现快速排序的非递归算法,可根据基准元素

为实现快速排序的非递归算法,可根据基准元素

快速排序非递归

快速排序是一种基于分治的排序算法,其基本思想是选定一个基准元素,然后将待排序数组中小于等于基准元素的元素放到其左侧,大于基准元素的元素放到其右侧,然后对左右两个子数组递归地进行同样的操作,直到整个数组有序。

快速排序的递归算法非常容易理解,但是由于其递归深度可能很大,可能导致栈溢出等问题。因此,我们可以考虑使用非递归算法来实现快速排序。非递归的快速排序算法通常使用栈来实现,将待排序区间的左右端点压入栈中,每次弹出一个区间并对其进行分割,直到栈为空为止。

  1. #include <stack>
  2. #include <algorithm>
  3. using namespace std;
  4. void quickSortNonRecursive(int arr[], int left, int right) {
  5. stack<pair<int, int>> stk;
  6. stk.push({left, right});
  7. while (!stk.empty()) {
  8. int l = stk.top().first, r = stk.top().second;
  9. stk.pop();
  10. if (l >= r)
  11. continue;
  12. int pivot = arr[l + rand() % (r - l + 1)];
  13. int i = l - 1, j = r + 1;
  14. while (i < j) {
  15. do i++; while (arr[i] < pivot);
  16. do j--; while (arr[j] > pivot);
  17. if (i < j)
  18. swap(arr[i], arr[j]);
  19. }
  20. stk.push({l, j}), stk.push({j + 1, r});
  21. }
  22. }

在上面的代码中,我们使用了一个pair<int, int>类型的栈来保存待排序的区间,每次取出栈顶元素,并对其进行分割。其中,我们使用rand()函数随机选择一个基准元素,以增加算法的随机性,防止出现最坏情况,提高排序的效率。同时,我们使用了双指针i和j来进行分割,i指向左侧子数组的末尾,j指向右侧子数组的开头,当i和j相遇时,分割完成。

 

归并排序非递归

归并排序是另一种基于分治思想的排序算法,其基本思想是将待排序数组分成两个子数组,对每个子数组递归地进行排序,最后将两个有序子数组合并成一个有序数组。归并排序的递归算法非常容易实现,但同样存在递归深度过大的问题。因此,我们可以使用非递归算法来实现归并排序。

非递归归并排序算法的核心思想是利用循环将数组不断地分成长度为2的子数组,然后将相邻的两个子数组合并成一个有序的大数组,不断循环,直到整个数组有序。具体实现中,我们使用了一个类似于归并排序中的merge函数来实现数组的合并,同时使用了一个长度为数组长度的临时数组来存储中间结果。

  1. #include <stack>
  2. using namespace std;
  3. void mergeSortUnRec(int* arr, int n)
  4. {
  5. int* help = new int[n];
  6. memset(help, 0, sizeof(int) * n);
  7. stack<pair<int, int> > stk1, stk2;
  8. stk1.push({ 0,n - 1 });
  9. while (!stk1.empty())
  10. {
  11. auto p = stk1.top();
  12. stk1.pop();
  13. if (p.first >= p.second)
  14. continue;
  15. stk2.push(p);
  16. int m = p.first + (p.second - p.first) / 2;
  17. stk1.push({ m + 1,p.second });
  18. stk1.push({ p.first,m });
  19. }
  20. //merge
  21. while (!stk2.empty())
  22. {
  23. int l = stk2.top().first, r = stk2.top().second;
  24. stk2.pop();
  25. int m = l + (r - l) / 2;
  26. int cur1 = l, cur2 = m + 1, cur3 = l;
  27. while (cur1 <= m && cur2 <= r)
  28. {
  29. if (arr[cur1] < arr[cur2])
  30. help[cur3++] = arr[cur1++];
  31. else
  32. help[cur3++] = arr[cur2++];
  33. }
  34. while (cur1 <= m)
  35. help[cur3++] = arr[cur1++];
  36. while (cur2 <= r)
  37. help[cur3++] = arr[cur2++];
  38. memcpy(arr + l, help + l, sizeof(int) * (r - l + 1));
  39. }
  40. delete[] help;
  41. }

在上述代码中,我们定义了两个pair类型的栈,其中pair的第一个元素表示子数组的左端点,第二个元素表示子数组的右端点。首先,我们利用stk1作为辅助将整个数组划分成若干个子数组,并将这些子数组入栈stk2。接下来,我们不断地从栈stk2中取出两个子数组,进行归并操作,重复这个过程,直到栈为空。

也可以不用栈用循环,也可以达到同样的目的

  1. void merge(int arr[], int l, int m, int r) {
  2. int i = l, j = m + 1, k = 0;
  3. int* tmp = new int[r - l + 1];
  4. while (i <= m && j <= r) {
  5. if (arr[i] <= arr[j]) tmp[k++] = arr[i++];
  6. else tmp[k++] = arr[j++];
  7. }
  8. while (i <= m)
  9. tmp[k++] = arr[i++];
  10. while (j <= r)
  11. tmp[k++] = arr[j++];
  12. for (i = l, k = 0; i <= r; i++, k++)
  13. arr[i] = tmp[k];
  14. delete[] tmp;
  15. }
  16. void mergeSortNonRecursive(int arr[], int n) {
  17. for (int sz = 1; sz < n; sz *= 2) {
  18. for (int i = 0; i < n - sz; i += sz * 2) {
  19. merge(arr, i, i + sz - 1, min(i + sz * 2 - 1, n - 1));
  20. }
  21. }
  22. }

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/703511
推荐阅读
相关标签
  

闽ICP备14008679号