别纠结Swap分区位置了!在Ubuntu SSD+HDD混合RAID1环境下,这样规划分区更合理
2026/6/1 10:12:06
快速排序是一种基于交换的排序算法,通过分治策略将待排序序列划分为两部分。算法首先选取基准元素(通常为首元素),使用双指针low和high从序列两端向中间扫描,确保low指针左侧元素均小于基准,high指针右侧元素均大于等于基准。通过不断交换元素位置,最终将基准元素放置到正确位置,完成一次划分。然后递归地对左右子序列重复上述过程,直至所有元素有序。示例中展示了以49为基准的一次完整划分过程,通过双指针交替移动和元素交换实现排序。该算法平均时间复杂度为O(nlogn),是一种高效的排序方法。
基于“交换”的排序:根据序列中两个元素关键字的比较结果来对换这两个记录在序列中的位置
//用第一个元素将待排序序列分成左右两个部分intPartition(intA[],intlow,inthigh){intpivot=A[low];//第一个元素作为枢轴while(low<high&&A[high]>=pivot)--high;A[low]=A[high];//比枢轴小的元素移动到左端while(low<high&&A[low]<=pivot)++low;A[high]=A[low];//比枢轴大的元素移动到右端}A[[low]=pivot;//枢轴元素存放到最终位置returnlow;}93//快速排序94voidQuickSort(intA[],intlow,inthigh){95if(low&high){//递归跳出的条件96intpivotpos=partition(A,low,high);//划分97QuickSort(A,low,pivotpos-1);//划分左子表98QuickSort(A,pivotpos+1,high);//划分右子表99}100}if(low< high),接下来会调用Partition这个函数int pivotpos= partition(A, low, high);,这个函数的功能就是进行一次划分,我们要把a这个数组的low到high内的元素进行一个划分,所以接下来在函数调用栈当中会压入和Partition这个函数相关的一些的信息,同时记录QuickSort函数执行到了第几行,此时是执行到了96行(#96)int pivot=A[Low];while(low<high)while(low<high&&A[high]>==pivot)--high;A[low]=A[high];while(low<high&&A[low]<=pivot)++low;A[high]=A[low];A[high]=A[low];或者A[low]=A[high];不再起作用,并且可以跳出外层循环,将pivot的值复制到low和high一起指向的位置A[low]=pivot;int pivotpos=partition(A, low, high);QuickSort(A, low, pivotpos-1);,此时将low = 0,high等于2,的QuickSort函数信息压入栈中if(low<high),因此可以直接返回执行第二层QuickSort,通过查看这一层的信息得知之前是执行到了第97行,因此此时执行第98行,也就是划分右子表QuickSort(A,pivotpos+1,high);QuickSort(A,pivotpos+1,high);快速排序是所有内部排序算法中平均性能最优的排序算法
若每一次选中的“枢轴”将待排序序列划分为很不均匀的两个部分,则会导致递归深度增加,算法效率变低
若每一次选中的“枢轴”将待排序序列划分为均匀的两个部分,则递归深度最小,算法效率最高
总结:若初始序列有序或逆序,则快速排序的性能最差(因为每次选择的都是最靠边的元素)
普通的快速排序可以应用于链表,但由于链表结构的特性,其性能优势不如在数组上明显
方法
small和cur)。small指针指向已处理部分中所有小于基准的节点的最后一个。cur指针遍历链表。当cur指向的节点值小于基准值时,将small指针后移,然后交换small和cur节点的值。这样就能将小于基准的节点逐步归拢到链表前半部分。small指针所指节点交换值。此时,基准节点就位于正确位置,其左边节点的值都小于它,右边节点的值都大于等于它。// 交换函数voidSwap(int*a,int*b){inttemp=*a;*a=*b;*b=temp;}// 快速排序辅助函数(划分左右子表)intPartition(intarr[],intlow,inthigh){// 优化:随机选择基准,避免最坏情况intrandomIndex=low+rand()%(high-low+1);Swap(&arr[low],&arr[randomIndex]);// 将随机基准交换到首位intpivot=arr[low];while(low<high){// 从右往左找到一个小于基准元素的数while(low<high&&arr[high]>=pivot)high--;arr[low]=arr[high];// 覆盖// 从左往右找到一个大于基准元素的数while(low<high&&arr[low]<=pivot)low++;// 修正:low++arr[high]=arr[low];// 覆盖}arr[low]=pivot;// 基准归位returnlow;}// 快速排序主函数voidQuickSort(intarr[],intlow,inthigh){if(low<high){// 划分子表intpivot=Partition(arr,low,high);// 递归左子表QuickSort(arr,low,pivot-1);// 递归右子表QuickSort(arr,pivot+1,high);}}// 快速排序启动函数voidQuickSortStrart(intarr[],intlength){intlow=0,high=length-1;// 将分别用low和high指向数组的首尾QuickSort(arr,low,high);}// 快速排序辅助函数(划分左右子表)intPartition(intarr[],intlow,inthigh){intpivot=arr[low];// 定下基准元素while(low<high){// 从右往左找到一个小于基准元素的数while(low<high&&arr[high]>=pivot)high--;// 找到后将arr[high]覆盖到arr[low]arr[low]=arr[high];// 从左往右找到一个大于基准元素的数while(low<high&&arr[low]<=pivot)low++;// 找到后将arr[low]覆盖到arr[high]arr[high]=arr[low];}// 将基准元素插入到最终位置arr[low]=pivot;// 返回基准元素的位置returnlow;}// 交换两个元素的值voidswap(int*a,int*b){inttemp=*a;*a=*b;*b=temp;}// 三数取中函数,返回中位数的索引intmedianOfThree(intarr[],intlow,inthigh){// 计算中间位置的索引,避免直接相加可能导致的整数溢出intmid=low+(high-low)/2;// 通过三次比较,对arr[low], arr[mid], arr[high]进行排序// 目标:使得 arr[low] <= arr[mid] <= arr[high]if(arr[mid]<arr[low]){swap(&arr[low],&arr[mid]);}if(arr[high]<arr[low]){swap(&arr[low],&arr[high]);}if(arr[high]<arr[mid]){swap(&arr[mid],&arr[high]);}// 此时,arr[mid]就是三个元素中的中位数// 返回中位数的索引returnmid;}// 三数取中法选择基准快速排序voidMidQuickSort(intarr[],intlow,inthigh){if(low<high){// 1. 使用三数取中法选择基准,并交换到起始位置intmidIndex=medianOfThree(arr,low,high);swap(&arr[low],&arr[midIndex]);// 2. 进行分区操作intpivotIndex=Partition(arr,low,high);// 3. 递归排序左右子数组MidQuickSort(arr,low,pivotIndex-1);MidQuickSort(arr,pivotIndex+1,high);}// 当 low >= high 时,递归终止}注:408原题中说,对所有尚未确定最终位置的所有元素进行一遍处理称为“一趟”排序,因此一次“划分”≠一趟排序。一次划分可以确定一个元素的最终位置,而一趟排序也许可以确定多个元素的最终位置。
八更😉
如果想查看更多章节,请点击:一、数据结构专栏导航页