算法思想:
设置两个指针,一个i指针初值为low和一个j指针初值为high,j指针从左往右移,当j指向的元素小于枢轴元素,将该元素放到枢轴元素左边,i指针从右往左移,当i指向的元素大于枢轴元素,将该元素放到枢轴元素右边
从上图可知49已经排序完,并且将左右两边分为了两个子表,接下来再对两个子表进行快速排序
左子表:
右子表:
接下来的步骤继续将76划分为左右两个子表,继续进行快速排序
代码实现(重点)
//用第一个元素将待排序序列划分成左右两个部分
int Partition(int A[], int low, int high) {
int pivot = A[low];//第一个元素作为枢轴
while (low < high) {//用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[low] = pivot;//枢轴元素存放到最终位置
return low;//返回存放枢轴的最终位置
}
//快速排序
void QuickSort(int A[], int low, int high) {
if (low < high) {//递归跳出的条件
int pivotpos = Partition(A, low, high);//划分
QuickSort(A, low, pivotpos - 1);//划分左子表
QuickSort(A, pivotpos + 1, high);//划分右子表
}
}
代码解释:
首先需要一个递归调用栈
进入第一层的QuickSort函数,传入数据和划分左右子表,low=0,high=7,#96表示代码执行的行数是在第96行:
第一层划分结果,传出low的值是3,第一层的pivotpos=3;
接下来划分左子表,进入第二层的QuickSort函数,low=0,high=pivotpos-1,此时第一层还压在栈中
划分完后第二层pivotpos=1,接下来开始划分左子表的左子表,进入第三层QuickSort函数,low=0,high=pivotpos-1;
划分完左子表的左子表后,因为第三层的low=high,所以退回第二层,接下来进行第二层的划分右子表,进入第三层QuickSort,low=pivotpos+1,high=2;
因为low=high,所以无需处理数据,直接返回第二层QuickSort函数
接下来返回第一层QuickSort函数,开始运行划分右子表代码,进入第二层QuickSort函数,low=4,high=7;
在第二层中处理完后返回low值为6,得到第二层的pivotpos=6,开始进行第二层划分左子表,low=4,high=5
在第三层中调用QuickSort函数,进入第四层,得出第三层pivotpos=4,同时因为low=high退出第四层,返回第三层;
在第三层开始执行划分左子表操作,low=4,high=pivotpos-1,进入第四层QuickSort
因为low>high,所以返回第三层,开始执行划分右子表操作,low=pivotpos+1,high=5
因为low=high,所以返回第三层,因为第三层代码执行完毕,返回第二层,开始执行划分右子表操作,low=pivotpos+1,high=7
因为low=high,所以返回第二层,又因为第二层代码执行完毕,所以返回第一层,第一层代码也已经执行完毕,递归结束;
算法效率分析
时间复杂度=O(n*递归层数)
Partition函数时间复杂度:O(n)
空间复杂度=O(递归层数)
平均时间复杂度:
比较好的情况:
最坏的情况:
优化思路:
递归层数(转换为二叉树的高度进行判断)
快速排序算法的稳定性:
不稳定
总结: