ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

剑指Offer-快速排序

2019-12-23 23:55:50  阅读:252  来源: 互联网

标签:Offer int data 基准值 high low small 排序 快速


剑指Offer上的快速排序的Partition函数与我在数据结构书上学到的不一样,因此就想要探索下这两种不同的处理方式。

1.基本思想

快速排序的基本思想是基于分治法。在待排序表L[1...n]中任取一个元素pivot作为基准,通过一趟排序将待排序表划分为独立的两部分L[1...k-1]和L[k+1...n],使得L[1...k-1]中所有元素小于pivot,L[k+1...n]中所有元素大于或等于pivot,则pivot放在了其最终位置L(k)上。而后递归地对两个子表重复上述过程,直至每部分内只有一个元素或空为止,即所有元素放在了其最终位置上。

2.剑指Offer上的Partition实现

 1 // Partition为分割函数, length表示data数组的长度
 2 int Partition(int data[], int length, int low, int high) {
 3     if (data == nullptr || length <= 0 || low < 0 || high >= length) {
 4         return 1;
 5     }
 6     
 7     // 在[low, high]区间中随机取一个基准值,并将其换到区间最末尾
 8     int index = RandomInRange(low, high);
 9     Swap(&data[index], &data[high]);
10     
11     // small在low的前面一位
12     int small = low - 1;
13        
14     for (index = low; index < high; ++index) {
15         if (data[index] < data[high]) {
16             // ++small后表示大于基准值的第一个数的下标
17             // 如果不存在大于基准值的数,则表示当前比较的数字下标
18             ++small;
19 
20             // 交换后的small表示小于基准值的最后一个数字的下标
21             if (small != index) {
22                 Swap(&data[index], &data[small]);
23             }
24         }
25     }
26     
27     // ++small后表示大于基准值的第一个数的下标
28     ++small;
29     Swap(&data[small], &data[high]);
30     
31     return small;
32     
33 }

 

快速排序其它函数实现如下:

 1 // 生成一个随机数,范围在[low,high),是一个前闭后开的区间
 2 int RandomInRange(int low, int high) {
 3     return rand() % (high - low) + low;
 4 }
 5 
 6 // 交换两个整数
 7 void Swap(int* left, int* right) {
 8     int temp  = *left;
 9     *left = *right;
10     *right = temp;
11 }
12 
13 // 快速排序函数
14 void QuickSort(int data[], int length, int low, int high) {
15     if (low == high) {
16         return;
17     }
18     
19     int index = Partition(data, length, low, high);
20     
21     if (index > low) {
22         QuickSort(data, length, low, index - 1);
23     }
24     
25     if (index < high) {
26         QuickSort(data, length, index + 1, high);
27     }
28 }
29 
30 // 数据打印
31 void PrintData(int data[], int length) {
32     for (int i = 0; i < length; ++i) {
33         std::cout << data[i] << " ";
34     }
35     
36     std::cout << std::highl;
37 }
38 
39 int main() {
40     // 以系统时间作为随机函数种子
41     srand((unsigned)time(nullptr));
42 
43     int const length = 10;
44     
45     int data[length];
46 
47     // 生成随机数
48     for (int i = 0; i < length; ++i) {
49         data[i] = RandomInRange(1, length*length);
50     }
51     
52     // 打印生成的随机数
53     PrintData(data, length);
54     
55     // 调用快排函数进行排序
56     QuickSort(data, length, 0, length - 1);
57   
58     // 打印快速排序后的数
59     PrintData(data, length);
60     
61     return 0;
62     
63 }

 

初始顺序为{49, 38, 65, 97, 76, 13, 27},基准值为49的数据的第一趟快速排序的实现如下所示:

 

 

第一趟排序完之后基准值49之前的{27, 38, 13}都比49小,基准值49之后的{76, 65, 97}都比49大。

3.一般教材上的Partition实现

 1 // Partition为分割函数
 2 int Partition(int data[], int low, int high) {
 3 
 4     // 将当前表中第一个元素设为基准值,对表进行划分
 5     int pivot = data[low]; 
 6 
 7     // 循环跳出条件
 8     while (low < high) {
 9         while (low < high && data[high] >= pivot) {
10             --high;
11         }
12 
13         // 将比基准值小的元素移动到左端
14         data[low] = data[high];
15 
16         while (low < high && data[low] <= pivot) {
17             ++low;
18         }
19 
20         // 将比基准值大的元素移动到右端
21         data[high] = data[low];
22     }
23 
24     // 基准元素存放到最终位置
25     data[low] = pivot;
26 
27     // 返回存放基准值的最终位置
28     return low;
29 }

 

快速排序其它函数实现如下:

 

 1 void QuickSort(int data[], int low, int high) {
 2     // 递归跳出条件
 3     if (low < high) {
 4         // 将data[low...high]一分为二,pivotpos是基准值
 5         int pivotpos = Partition(data, low, high);
 6 
 7         // 对左子表进行递归排序
 8         QuickSort(data, low, pivotpos - 1);
 9 
10         // 对右子表进行递归排序
11         QuickSort(data, pivotpos + 1, high);
12     }
13 }

 

初始顺序为{49, 38, 65, 97, 76, 13, 27},基准值为49的数据的第一趟快速排序的实现如下所示:

 

 

第一趟排序完之后基准值49之前的{27, 38, 13}都比49小,基准值49之后的{76, 97, 65}都比49大。

4.总结

可以看出,上述这两种思想导致的运行过程是不同的,前者是用small指代小于标准元素的最右位置,在遍历过程中进行交换操作来保证small左边都是小于标准元素的元素,而后者是用low,high分别表示小于和大于基准值的集合边界位置,所以后者更浅显易懂。

 

标签:Offer,int,data,基准值,high,low,small,排序,快速
来源: https://www.cnblogs.com/codeapes666/p/12089134.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有