对快排的递归, 非递归, 和扩展的思考.
一. 对于快排的定义, 和理解文章的要求:
要求:
1>对基础的数据结构有一定的熟悉, 和相关的认识.
2>对c++的基础的语法和STL容器有相关的了解.
定义:
快速排序(Quick Sort)的基本思想是: 通过一趟的排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部记录的关键字小, 则可以分别对这两部分记录继续进行排序, 已达到整个序列有序的目的(大话数据结构 程杰P417).
二. 代码分析,
<1>递归中快排分析.
1 #include<stdio.h> 2 #include<iostream> 3 #include<vector> 4 using namespace std; 5 /* 6 交换两个vector<int>的两个内容的值: 7 */ 8 void swap(vector<int> &array, int left, int right) 9 { 10 int tmp = array[left]; 11 array[left] = array[right]; 12 array[right] = tmp; 13 } 14 15 /* 16 选取第一个值, 并把比起大的放到后面, 17 比起小的放到前面. 18 */ 19 int patition(vector<int> &array, int left, int right) 20 { 21 int pos = array[left];//对比的位置, 上图的tmp 22 while(left < right) 23 { 24 //从后面找较小的放到前面: 25 while(left < right && pos <= array[right]) {right--;} 26 swap(array, left, right); 27 28 //找前面找较大的放到后面: 29 while(left < right && array[left] <= pos){left++;} 30 swap(array, left, right); 31 } 32 return left; 33 } 34 35 /* 36 快排函数, 并作为递归函数: 37 */ 38 void Qsort(vector<int> &array, int left, int right) 39 { 40 if(left < right) 41 { 42 //返回已经调整的位置: 43 int pos = patition(array, left, right); 44 Qsort(array, left, pos-1); 45 Qsort(array, pos+1, right); 46 } 47 } 48 49 int main() 50 { 51 vector<int> array = {7, 5, 8, 2, 6, 4}; 52 Qsort(array, 0, array.size()-1); 53 54 for(auto i:array) 55 { 56 cout << i << " "; 57 } 58 cout << endl; 59 return 0; 60 }
_1测试结果如下:

支持环境为 Linux下 g++ -std=c++11.
_2分析Qsort(vector<int> &array, int left, int right)

因为 left < right则进入条件中:
执行 int pos = patition(array, left, right);操作,
patition作用:
就是要先选取当中的一个关键字, 比如7, 然后在想尽办法将它放到一个位置, 使它左边的值
都比它小, 右边的值都比它大.
而pos成为了关键中枢(比左边都大, 比右边都小)。

好吧,到这里后, 一步一步来分析:

行, 到这里我们进行了第一次patition结束, 再往下分析


<2>将递归转化为非递归.
_1思路,
将递归转化为非递归, 如上所示, 递归中用到的数据为 pos right, left等作为判断条件
如果递归的话, pos+1 < right || pos-1 > left 条件
递归退出时 pos == right || pos == right
而将递归转化为非递归是, 借用stack和pait<int left, int right>来进行操作
_2代码如下:
#include<iostream> #include<stack> #include<vector> #include<utility> using namespace std; /* 使用栈stack<pair>和pair<int, int>来 解决递归转化为非递归问题. */ /* 同上: */ void swap(vector<int> &array, pair<int, int> &elem) { int temp = array[elem.first]; array[elem.first] = array[elem.second]; array[elem.second] = temp; } /* 同上: */ int patition(vector<int> &array, pair<int, int> elem) { int pos = array[elem.first]; while(elem.first < elem.second) { while(elem.first < elem.second && array[elem.second] >= pos) { elem.second--; } swap(array, elem); while(elem.first < elem.second && array[elem.first] <= pos) { elem.first++; } swap(array, elem); } return elem.first; } /* 使用stack<pait<int, int>>对其的控制, */ void Qsort(vector<int> &array) { stack<pair<int, int>> st; pair<int, int> pa = make_pair(0, array.size()-1); st.push(pa); while(!st.empty()) { pa = st.top(); st.pop(); int pos = patition(array, pa); if(pos != pa.first) { st.push(make_pair(pa.first, pos-1)); } if(pos != pa.second) { st.push(make_pair(pos+1, pa.second)); } } } int main() { vector<int> array = {7, 5, 8, 2, 6, 4}; Qsort(array); for(auto i: array) { cout << i << " "; } cout << endl; }
_4.测试结果.

_5.运行环境如上.
_6.理解如下:

<3>是否可以将单链表进行快排操作.
_1思路理解:
和前面的类似, 但是如何找到它的迭代器前驱, ???
来一次单链表的循环, 这个不是很高效, 但是是一种问题的解决思路.
_2代码如下:
#include<string> #include<forward_list> #include<stack> #include<utility> #include<iostream> #include<cstdio> /* 使用了单链表来完成快排. */ using namespace std; /* 使用了using 声明了myType类型为迭代器 */ using myType = forward_list<int>::iterator ; //同上 void swap(myType &first, myType &second) { int tmp = *first; *first = *second; *second = tmp; } /* 通过一边循环来找到tmp的前驱的迭代器: */ myType getPtrFront(forward_list<int> &single, myType tmp) { myType ptr = single.begin(); for(myType p = ++(single.begin());\ p != tmp; ++p, ++ptr){} return ptr; } /* 比前一个更加优化, 来找到前驱迭代器: */ myType getPFront(pair<myType, myType> pa) {
myType tmp = pa.first++; while(pa.first != pa.second) { pa.first++; tmp++; } return tmp; } myType patition(forward_list<int> &single, pair<myType, myType> pa) {
myType tmp = pa.first; while(pa.first != pa.second) { while(pa.first != pa.second && *(pa.second) >= *tmp) { pa.second = getPFront(pa); } swap(tmp, pa.second); tmp = pa.second;//对其迭代器tmp的维护 while(pa.first != pa.second && *tmp >= *(pa.first)) { pa.first++; } swap(tmp, pa.first); tmp = pa.first; } return tmp; } void Qsort(forward_list<int> &single) { pair<myType, myType> pa(single.begin(), getPtrFront(single, single.end())); stack<pair<myType, myType>> st; st.push(pa); while(!st.empty()) { pa = st.top(); st.pop(); myType tmp = patition(single, pa); if(pa.first != tmp) { st.push(make_pair(pa.first, getPtrFront(single, tmp))); } if(pa.second != tmp) { st.push(make_pair(++tmp, pa.second)); } } } int main() { forward_list<int> single_list = {7, 5, 8, 2, 6, 4}; Qsort(single_list); for(auto i : single_list) { cout << i << " "; } cout << endl; return 0; }
_3测试如下:

_4情景分析:
其主要来找到其的前驱迭代器, 来完成后上述过程, 思路类似.
<4>是否可以通过快排来对双链表进行操作.
_1.和其上类似,
_2.代码如下:
#include<cstdio> #include<string> #include<list> #include<stack> #include<utility> #include<iostream> #include<vector> using namespace std; using myType = list<int>::iterator ; void swap(myType &first, myType &second) { int tmp = *first; *first = *second; *second = tmp; } myType patition(list<int> &dlist, pair<myType, myType> pa) { myType tmp = pa.first; while(pa.first != pa.second) { while(pa.first != pa.second && *(pa.second) >= *tmp) { --(pa.second); } swap(tmp, pa.second); tmp = pa.second; while(pa.first != pa.second && *tmp >= *(pa.first)) { ++(pa.first); } swap(tmp, pa.first); tmp = pa.first; } return tmp; } void Qsort(list<int> &dlist) { pair<myType, myType> pa(dlist.begin(), --dlist.end()); stack<pair<myType, myType>> st; st.push(pa); while(!st.empty()) { pa = st.top(); st.pop(); myType tmp = patition(dlist, pa); if(pa.first != tmp) { myType t = --tmp; st.push(make_pair(pa.first, t)); tmp++; } if(pa.second != tmp) { myType t = ++tmp; st.push(make_pair(t, pa.second)); tmp--; } } } int main() { vector<int> array = {7, 5, 8, 2, 6, 4, 3, 10, 0}; list<int> d_list(array.begin(), array.end()); Qsort(d_list); for(auto i : d_list) { cout << i << " "; } cout << endl; return 0; }
_3.思路分析
在其中主要是传进去的是迭代器, 对其进行操作. 思路类似.
<5>. 效率分析.
快排的时间复杂度取决于快排的深度, 类似于递归树,
最优的情况下:
一分为二, 一个平衡的二叉树
则:
T(n) = 2T(n/2) + n;
则:
T(n) <= O(nlogn);
最坏情况下:
它是一个斜树, O(n^2)
四.总结:
本文章主要对快排进行了解, 和分析, 并对其进行了扩展。并参考了 大话数据结构, 数据结构(严蔚敏2th)等.
如有任何问题.请拍砖.

浙公网安备 33010602011771号