当前位置:   article > 正文

数据结构之排序

数据结构之排序

1.排序的概念及常见的排序算法

   1.1排序的概念

  • 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
  • 稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
  • 内部排序:数据元素全部放在内存中的排序。
  • 外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

   1.2常见排序算法

2.常见排序算法的实现

 2.1直接插入排序

  2.1.1基本思想

          直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的记录按其关键码值的        大 小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有      序序列。

2.1.2代码实现

  1. void InsertSort(int* a, int n) {
  2. //[0,end]的区间有序 把end+1的数向前插入
  3. for (int i = 0; i < n - 1; i++) {
  4. int end = i;
  5. int tmp = a[end + 1];
  6. while (end >= 0)
  7. {
  8. if (tmp < a[end])
  9. {
  10. a[end + 1] = a[end];
  11. end--;
  12. }
  13. else {
  14. break;
  15. }
  16. }
  17. a[end + 1] = tmp;
  18. }
  19. }

2.2希尔排序

2.2.1基本思想

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

2.2.2代码实现

  1. void ShellSort(int* a, int n) {
  2. //希尔分为预排序和插入排序,预排序是分组写
  3. int gap = n;
  4. while (gap > 1)
  5. {
  6. gap = gap / 3 + 1;
  7. for (int i = 0; i < n - gap; i++)
  8. {
  9. int end = i;
  10. int tmp = a[end + gap];
  11. while (end >= 0)
  12. {
  13. if (tmp < a[end])
  14. {
  15. a[end + gap] = a[end];
  16. end -= gap;
  17. }
  18. else
  19. {
  20. break;
  21. }
  22. }
  23. a[end + gap] = tmp;
  24. }
  25. }
  26. }

2.3选择排序

2.3.1基本思想

在元素集合array[i]--array[n-1]中选择关键码最大(小)的数据元素若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换在剩余的array[i]--array[n-2](array[i+1]--array[n-1])集合中,重复上述步骤,直到集合剩余1个元素。

2.3.2代码实现

        这里的代码是对选择排序的优化版本,它可以同时选出最大值和最小值。

  1. //选择排序
  2. void SelectSort(int* a, int n) {
  3. //遍历选出最小的和最大的数的下标,再进行交换最小的换到最左边,最大的换到最右边
  4. int begin = 0,end=n-1;
  5. while (begin < end)
  6. {
  7. int min = begin, max = begin;//每次循环后缩小区间
  8. for (int i = begin + 1; i <= end; i++)
  9. {
  10. if (a[i] < a[min])
  11. {
  12. min = i;
  13. }
  14. if (a[i] > a[max])
  15. {
  16. max = i;
  17. }
  18. }
  19. //swap(&a[begin], &a[min]);
  20. 防止最大的下标和开始一样,最小的和end一样,导致重复两次置换数组元素
  21. //if (max == begin)
  22. //{
  23. // max = min;
  24. //}
  25. //swap(&a[end], &a[max]);
  26. swap(&a[end], &a[max]);
  27. if (min == end)
  28. {
  29. min = max;
  30. }
  31. swap(&a[begin], &a[min]);
  32. begin++;
  33. end--;
  34. }
  35. Print(a, n);
  36. }

2.4堆排序

2.4.1基本思想

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

2.4.2代码实现

  1. //堆排序
  2. void AdjustDown(HPDataType* a, int parent,int n) {
  3. int child = parent * 2 + 1;
  4. while (child<n)
  5. {
  6. //选出左右孩子里小的那个,child+1要小于n,因为可能只有一个孩子
  7. if ((child+1)<n && a[child+1] < a[child])
  8. {
  9. child++;
  10. }
  11. if (a[child] < a[parent])
  12. {
  13. swap(&a[child], &a[parent]);
  14. parent = child;
  15. child = parent * 2 + 1;
  16. }
  17. else
  18. {
  19. break;
  20. }
  21. }
  22. }
  23. void HeapSort(int* a, int n) {
  24. //升序建大堆,降序建小堆
  25. int i = 0;
  26. for (i = (n - 1 - 1) / 2; i >= 0; i--)
  27. {
  28. AdjustDown(a, i, n);
  29. }
  30. int end = n - 1;//end记录最后一个节点的下标,把第一个节点和最后一个节点换位置然后向下调整
  31. while (end>0)
  32. {
  33. swap(&a[0], &a[end]);
  34. AdjustDown(a, 0, end);
  35. end--;
  36. }
  37. }

2.5冒泡排序

2.5.1基本思想      

 冒泡排序是在数组中对相邻两个元素进行对比,依次循环知道所有数据有序。属于最简单的排序算法之一。

2.5.2代码实现

  1. //冒泡排序
  2. void BubbleSort(int* a, int n) {
  3. for (int j = 0; j < n; j++)
  4. {
  5. for (int i = 0; i < n-j-1; i++)
  6. {
  7. if (a[i] > a[i + 1])
  8. {
  9. swap(&a[i], &a[i + 1]);
  10. }
  11. }
  12. }
  13. Print(a, n);
  14. }

2.6快速排序

2.6.1基本思想

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

2.6.2Hoare版本的快速排序

  1. //经典快排
  2. void PartSort1(int* a, int left, int right) {
  3. int begin, end;
  4. begin = left, end = right;
  5. if (left >= right)
  6. return;//返回条件
  7. int keyi = left;
  8. while (left < right)
  9. {
  10. while(left<right&&a[right] >= a[keyi])//R找小,R必须先走,必须要有left<right的判断条件要不right和left相遇无法判断
  11. {
  12. right--;
  13. }
  14. while(left<right&&a[left] <= a[keyi])//L找大
  15. {
  16. left++;
  17. }
  18. swap(&a[left], &a[right]);
  19. }
  20. swap(&a[left], &a[keyi]);
  21. keyi = left;
  22. // [begin,keyi]keyi[keyi+1,end]
  23. PartSort1(a, begin, keyi);
  24. PartSort1(a, keyi + 1, end);
  25. }

2.6.3双指针法快速排序

  1. void PartSort3(int* a, int left, int right) {
  2. int prev = left,cur=left+1;
  3. if (left >= right)
  4. return;
  5. int keyi = left;
  6. while (cur < right +1)
  7. {
  8. if (a[cur]<a[keyi])
  9. {
  10. prev++;
  11. swap(&a[prev], &a[cur]);
  12. }
  13. cur++;
  14. }
  15. swap(&a[prev], &a[keyi]);
  16. keyi = prev;
  17. //[left,keyi]
  18. PartSort3(a, left, keyi);
  19. PartSort3(a, keyi+1, right);
  20. }

2.6.4非递归版快速排序

借用数据结构栈来进行堆递归时栈帧的模拟,每一次把区间的端点值入到栈中,先入右端点再入左端点,出栈的时候先出左端点再出右端点。之后再以keyi为界限把区间再度二分。依次循环直到栈为空。

  1. void QuickSortNonR(int* a, int left, int right) {
  2. //栈中存放区间端点,先入右端点后入左端点。
  3. Stack st;
  4. StackInit(&st);
  5. StackPush(&st, right);
  6. StackPush(&st, left);
  7. while (!StackEmpty(&st))
  8. {
  9. int begin=StackTop(&st);
  10. StackPop(&st);
  11. int end = StackTop(&st);
  12. StackPop(&st);
  13. int cur = begin + 1, prev = begin, keyi = begin;
  14. while (cur <=end)
  15. {
  16. if (a[cur] < a[keyi])
  17. {
  18. prev++;
  19. swap(&a[prev], &a[cur]);
  20. }
  21. cur++;
  22. }
  23. swap(&a[prev], &a[keyi]);
  24. keyi = prev;
  25. //[begin,keyi]keyi[keyi+1,end]
  26. if (keyi + 1 < end)
  27. {
  28. StackPush(&st, end);
  29. StackPush(&st, keyi + 1);
  30. }
  31. if (keyi > begin)
  32. {
  33. StackPush(&st, keyi);
  34. StackPush(&st, begin);
  35. }
  36. }
  37. StackDestroy(&st);
  38. }

2.7归并排序

2.7.1基本思想

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。


2.7.2代码实现

  1. void _MergeSort(int* a, int begin, int end, int* tmp)
  2. {
  3. if (begin == end)
  4. return;
  5. int mid = (begin + end) / 2;
  6. // [begin, mid] [mid+1, end]
  7. _MergeSort(a, begin, mid, tmp);
  8. _MergeSort(a, mid+1, end, tmp);
  9. // 归并
  10. int begin1 = begin,end1 = mid;
  11. int begin2 = mid + 1,end2 = end;
  12. int i = begin;
  13. // 依次比较,取小的尾插tmp数组
  14. while (begin1 <= end1 && begin2 <= end2)
  15. {
  16. if (a[begin1] <= a[begin2])
  17. {
  18. tmp[i++] = a[begin1++];
  19. }
  20. else
  21. {
  22. tmp[i++] = a[begin2++];
  23. }
  24. }
  25. while (begin1 <= end1)
  26. {
  27. tmp[i++] = a[begin1++];
  28. }
  29. while (begin2 <= end2)
  30. {
  31. tmp[i++] = a[begin2++];
  32. }
  33. memcpy(a+begin, tmp + begin, sizeof(int) * (end - begin + 1));
  34. }

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

闽ICP备14008679号