在学习快速排序算法时,由于理解不对,出现了很多问题。后来在学习数据结构时才明白,故记之。
这里参考了两本书:但显然我校教材不太好理解。
快速排序算法的思想是:
选定枢纽元,将所有小于枢纽元的元素移动到枢纽元的左边,大于枢纽元的元素移动到枢纽元的右边。
主要步骤在于对序列的划分。
法一:用补空位的思想去理解(比较好理解的)
取序列中的第一个记录,以其关键码为标准划分其他记录,把关键码小的记录移动到表的左边,关键码大的记录移动到表的右边。
划分完成后表中间将留下一个空位,这就是作为比较标准的记录的正确位置。
{11,0,4,6,23,5,2,18,7,7} {7,0,4,6,23,5,2,18,7,7} {7,0,4,6,23,5,2,18,7,23} {7,0,4,6,7,5,2,18,7,23} {7,0,4,6,7,5,2,18,18,23} {7,0,4,6,7,5,2,7,18,23}
代码:
1 void quicksort(int k[],int low,int high) 2 { 3 if(low>=high) //如果没有记录或者只有一个记录 4 return; 5 int i=low,j=high;//i从前向后数,j从后向前数 6 int pivot=k[low];//选定第一个元素为关键元 7 while(i<j) //交换 8 { 9 while(i<j && k[j]>=pivot) --j; 10 if(i<j) 11 { 12 k[i]=k[j]; 13 i++; 14 } 15 while(i<j && k[i]<=pivot) ++i; 16 if(i<j) 17 { 18 k[j]=k[i]; 19 j--; 20 } 21 } 22 k[i]=pivot; 23 quicksort(k,low,i-1); 24 quicksort(k,i+1,high); 25 }
测试无问题....
法二:
取序列中的第一个记录,以其关键码为标准划分其他记录,把关键码小的记录移动到表的左边,关键码大的记录移动到表的右边。采用交换的方式。
最后停止时i的位置就是作为比较标准的记录的正确位置。再交换k[i]和[0]即可。
{11,0,4,6,23,5,2,18,7,7}
{11,0,4,6,7i,5,2,18,7,23j}
{11,0,4,6,7,5,2,7j,18i,23}
{7,0,4,6,7,5,2,11j,18i,23}
代码:
void swap(int& a,int& b) { int temp=a; a=b; b=temp; } void quicksort2(int k[],int low,int high) { if(low>=high) return;//如果没有记录或者只有一个记录 int i=low; int j=high+1; int pivot=k[low]; while(i<j) { i++; while(k[i]<pivot) i++; j--; while(k[j]>pivot) j--; if(i<j) swap(k[i],k[j]); } swap(k[low],k[j]); quicksort2(k,low,j-1); quicksort2(k,j+1,high); }
这两种写法不同,但思想是一样的。
平均复杂度均为O(nlogn) 在已经排序的序列中复杂度最高O(n2)
三:
三者取中快速排序:
因为每次划分成大小差不多的两个序列时算法效率更高,所以我们在k[low],k[(low+high)/2],k[high]中 寻找中间值
void quicksort3(int k[],int low,int high) { if(low>=high) return; //STEP1:选中间值元素 swap(k[(low+high)/2] ,k[low+1]); if(k[low+1]>k[high]) swap(k[low+1],k[high]); if(k[low]>k[high]) swap(k[low],k[high]); if(k[low+1]>k[low]) swap(k[low],k[low+1]); //STEP2: int i=low; int j=high+1; int pivot=k[low]; while(i<j) { i++; while(k[i]<pivot) i++; j--; while(k[j]>pivot) j--; if(i<j) swap(k[i],k[j]); } swap(k[low],k[j]); quicksort3(k,low,j-1); quicksort3(k,j+1,high); }
法四:
非递归快速排序:
非递归算法需要一个堆栈,储存一些待排序的子文件。由于元素较少时,直接插入排序算法的效率比快速排序效率更高,所以可以选定一个常数M,当文件长度>=M时调用算法Part,否则采用直接插入排序。
1 int part4(int k[],int low,int high) 2 { 3 4 //STEP1:选中间值元素 5 swap(k[(low+high)/2] ,k[low+1]); 6 if(k[low+1]>k[high]) swap(k[low+1],k[high]); 7 if(k[low]>k[high]) swap(k[low],k[high]); 8 if(k[low+1]>k[low]) swap(k[low],k[low+1]); 9 10 //STEP2: 11 int i=low; 12 int j=high+1; 13 int pivot=k[low]; 14 while(i<j) 15 { 16 i++; 17 while(k[i]<pivot) i++; 18 j--; 19 while(k[j]>pivot) j--; 20 if(i<j) 21 swap(k[i],k[j]); 22 } 23 swap(k[low],k[j]); 24 return j; 25 } 26 27 28 29 void insertsort(int k[],int n) 30 { 31 for(int i=1;i<n;i++) 32 { 33 int j=i; 34 int temp=k[i]; 35 while(i>0&&temp<k[j-1]) 36 { 37 k[j]=k[j-1]; 38 j--; 39 } 40 k[j]=temp; 41 } 42 } 43 44 void quicksort4(int k[],int low,int high,int M) 45 { 46 stack<int>s; 47 int temp; 48 int n=high-low+1; 49 s.push(0); 50 s.push(0); 51 while(low < high) 52 { 53 int mid=part4(k,low,high); 54 if((mid-low<M) && (high-mid<M)) 55 { 56 low=s.top(); s.pop(); 57 high=s.top();s.pop(); 58 continue; 59 } 60 if((mid-low<M)&&(high-mid>=M)) 61 { 62 low=mid+1;continue; 63 } 64 if((mid-low>=M)&&(high-mid<M)) 65 { 66 high=mid-1;continue; 67 } 68 if((mid-low>=M)&&(high-mid>=M)) 69 { 70 if(mid-low>high-mid) 71 { 72 s.push(mid-1);s.push(low); 73 low=mid+1; 74 } 75 else 76 { 77 s.push(high);s.push(mid+1); 78 high=mid-1; 79 } 80 } 81 } 82 insertsort(k,n); 83 }