Unlimited Blade Works

Unaware of loss.Nor aware of gain.

导航

对于快速排序算法的递归栈深度的一点改进

  前几天有人问了我一个关于快速排序的问题。起因是严蔚敏版数据结构第277页的一句话:“如果改写算法10.7,在一趟排序之后比较分割所得两部分的长度,且先对长度短的子序列中的记录进行快速排序,则栈的最大深度可降为O(logn)。”(注:这里的logn是log2n的简写)。

  因为对于原地排序而言,额外的空间复杂度应该是常数,但由于快速排序的实现一般是递归的方式,所以快速排序的额外空间复杂度不是常数,而是和递归深度相关。

  回到一开始的问题上来,刚看到那句话还觉得奇怪,因为话里的栈的深度是指函数递归调用的深度,这个和处理两个子序列的顺序应该是无关的,除非还在递归方面有其它改进,例如回溯到上上级。顺着这个思路来想,觉得改进栈的最大深度是有可能的。

  这个改进的主要思想应该是:用没处理的子节点代替父节点,以减少栈的深度。

  假设父节点A,子节点B、C。处理完B后,并不直接处理C而是回溯回A,并把C交到A这一级来处理。通过这种方法的确可以将栈的最大深度降到O(logn)。详细的数学证明就不写了。

  下面是具体的实现代码。代码里把两种快速排序都列出来了,以方便对比。实验结果也证实是在递归深度是在logn以内。

  1 /***
  2 *对于快速排序递归函数栈的深度的改进
  3 *author:Allen
  4 *date:2012-11-01
  5 *说明:
  6 *由于只是简单实现算法,对于代码风格没太在意。
  7 *原快速排序算法的代码是从网上找的,并做了一点修改。
  8 */
  9 #include <iostream>
 10 #include<ctime>
 11 using namespace std;
 12 const int a_size = 128;//带排序数列长度
 13 int a[a_size];
 14 void swap(int *pLeft,int *pRight)
 15 {
 16     int temp;
 17     temp = *pLeft;
 18     *pLeft= *pRight;
 19     *pRight = temp;
 20 }
 21 //原快速排序
 22 void qs(int begin,int end)
 23 {
 24     static int deep = 0;//递归深度
 25     static int allnum =0;//函数调用总次数
 26     static int mostDeep = 0;//最大递归深度
 27     ++allnum;
 28     ++deep;
 29     if(deep>mostDeep){
 30         mostDeep=deep;
 31     }
 32     int compare=a[begin], left =begin,right = end;
 33     if(abs(right-left)<=1)
 34     {
 35         --deep;
 36         if(left<right && a[left]>a[right]){
 37             swap(a[right],a[left]);
 38         }
 39         return;
 40     }
 41     while (left <right)
 42     {
 43         while ((left <right) && a[right]>=compare)
 44             right--;
 45         swap(a[left],a[right]);
 46         while ((left <right) &&(a[left] <compare))
 47             left++;
 48         swap(a[right],a[left]);
 49     }
 50     a[right] = compare;
 51     qs(begin,right-1);
 52     qs(right+1,end);
 53     --deep;
 54     if(deep<=0){
 55         cout<<"函数调用总次数:"<<allnum<<endl;
 56         cout<<"最大递归深度数:"<<mostDeep<<endl;
 57     }
 58 }
 59 //改进快排,每次递归函数中还剩一组未排序列,即回溯到上级。
 60 //优先排短的序列
 61 //递归函数参数表里还要保留两个未排序列的参数,返回给上级递归处理
 62 //可以认为是下级递归函数(B)完成一半原来任务(C)后,即将自身的函数栈释放,将另一半任务(D)仍交给上级函数(A)
 63 //由此另一半任务(D)执行时,所使用的函数栈深度和下级递归函数(B)的深度是一样的都是上级函数(A)+1
 64 //但是要注意顶级部分的函数仍然要处理掉C、D两个任务。
 65 void qs(int p_begin,int p_end,int &p_unBegin,int &p_unEnd)
 66 {
 67     static int deep = 0;//递归深度
 68     static int allnum =0;//函数调用总次数
 69     static int mostDeep = 0;//最大递归深度
 70     ++allnum;
 71     ++deep;
 72     if(deep>mostDeep){
 73         mostDeep=deep;
 74     }
 75     //    cout<<"递归深度:"<<deep << ' ' <<p_begin <<' ' <<p_end<<' ' <<p_unBegin<<' ' <<p_unEnd<<' ' <<endl;
 76     int compare=a[p_begin], left =p_begin,right = p_end;
 77     if(abs(right-left)<=1)
 78     {
 79         --deep;
 80         if(left<right && a[left]>a[right]){
 81             swap(a[right],a[left]);
 82         }
 83         p_unBegin=-1;
 84         p_unEnd=-1;
 85         return;
 86     }
 87     while (left <right)
 88     {
 89         while ((left <right) && a[right]>=compare)
 90             --right;
 91         
 92         swap(a[left],a[right]);
 93         while ((left <right) &&(a[left] <compare))
 94             ++left;
 95         
 96         swap(a[right],a[left]);
 97     }
 98     a[right] = compare;
 99     
100     int newBegin;
101     int newEnd;
102     int unBegin=p_begin;
103     int unEnd=p_end;
104     
105     if( (right-1)-p_begin <= p_end-(right+1) ){
106         newBegin=p_begin;
107         newEnd=right-1;
108         p_unBegin=right+1;
109         p_unEnd=p_end;
110         qs(newBegin,newEnd,unBegin,unEnd);
111         while(unBegin!=-1&&unEnd!=-1){
112             qs(unBegin,unEnd,unBegin,unEnd);
113         }
114         if(deep>1){
115             --deep;
116             return;
117         }
118     }else{
119         p_unBegin=p_begin;
120         p_unEnd=right-1;
121         newBegin=right+1;
122         newEnd=p_end;
123         qs(newBegin,newEnd,unBegin,unEnd);
124         while(unBegin!=-1&&unEnd!=-1){
125             qs(unBegin,unEnd,unBegin,unEnd);
126         }    
127         if(deep>1){
128             --deep;
129             return;
130         }
131     }        
132     //另一部分
133     qs(p_unBegin,p_unEnd,unBegin,unEnd);
134     while(unBegin!=-1&&unEnd!=-1){
135         qs(unBegin,unEnd,unBegin,unEnd);
136     }
137     --deep;
138     if(deep<=0){
139         cout<<"函数调用总次数:"<<allnum<<endl;
140         cout<<"最大递归深度数:"<<mostDeep<<endl;
141     }    
142 }
143 
144 void printArray(const int * p_arr,const int size){
145     for (int i=0;i<size;i++)
146     {
147 //        cout<<"array["<<i<<"] = "<<p_arr[i]<< ' ';
148         cout<< p_arr[i]<< ' ';
149     }
150     cout<<endl;
151 }
152 
153 int main()
154 {    
155     int i=0;
156     srand(time(0));
157     int b[a_size];//原数列数组
158     for (i =0;i< a_size;i++)
159     {
160         b[i] =rand()%a_size;
161         //    b[i] =a_size-i;
162         //    b[i] =i;
163     }
164     cout<<"排序前"<<endl;
165     printArray(b,a_size);
166     for (i= 0;i<a_size;i++)
167     {
168         a[i]=b[i];
169     }
170     cout<<"原来的排序后"<<endl;
171     qs(0,a_size-1);
172     printArray(a,a_size);
173     //下面为改进的
174     for (i= 0;i<a_size;i++)
175     {
176         a[i]=b[i];
177     }
178     cout<<"改进的排序后"<<endl;
179     int st=0;
180     int en=a_size-1;
181     qs(0,a_size-1,st,en);
182     printArray(a,a_size);
183     system("pause");
184     return 0;
185 }

  另外今天是万圣节。

posted on 2012-11-01 14:11  飞鸿无月  阅读(3443)  评论(0编辑  收藏  举报