快速排序笔记
写的脑子都抽了,果然实在做不出来还是得问一下ai。
我自己最后又自己写了一下,是这个:
#include<stdio.h>
int p,q,pivot,mid,temp;
int n;
int P[100100];
void quick(int P[100100],int l, int r){
if(l>=r){
return;
}
p = l;
q = r;
mid = (r+l)>>1;
pivot = P[mid];
while(p<=q){
while(P[p] < pivot){
p++;
}
while(P[q] > pivot){
q--;
}
if(p<=q){
temp = P[p];
P[p] = P[q];
P[q] = temp;
p++,q--;
}
}
quick(P, l, q);
quick(P, p, r);
}
int main(){
scanf("%d",&n);
for(int i = 0; i < n; i++)scanf("%d",&P[i]);
quick(P,0,n-1);
for(int i = 0; i < n; i++)printf("%d ",P[i]);
return 0;
}
总之思路就是,选出一个基准,然后两个指针往中间找,找到比基准大或者小的就停下来,交换,然后继续,直到他们交错,然后又对两边递归。
第k个数就是直接输出就行,这里代码飘了:
#include<stdio.h>
int pivot,p,q,n,mid,temp,k;
int P[100100];
void quick(int P[100100], int l, int r){
if(l>=r) return;
mid = (l+r)>>1;
pivot = P[mid];
p=l;
q=r;
while(p<=q){
while(P[p]<pivot)p++;
while(P[q]>pivot)q--;
if(p<=q){
temp = P[p];P[p] = P[q];P[q] = temp;
p++;q--;
}
}
quick(P,l,q);
quick(P,p,r);
}
int main(){
scanf("%d %d",&n,&k);
for(int i = 0; i < n;i++)scanf("%d",&P[i]);
quick(P, 0, n-1);
printf("%d",P[k-1]);
return 0;
}
快速排序代码易错点及对比报告
一、引言
在快速排序算法的实现过程中,容易出现多种逻辑错误,导致程序无法正确运行。本报告将对原错误代码与修正后的代码进行逐段对比,详细分析其中的易错点,帮助理解快速排序算法的正确实现逻辑。
二、代码对比与易错点分析
(一)基准值选择与处理
对比项目 | 原代码(行15-16) | 修正后代码(行15-16) | 易错点分析 |
---|---|---|---|
基准值定义 | mid = (l+r)>>1; ,直接使用 P[mid] 作为基准值,未单独存储 |
int mid = (l + r) / 2; int pivot = P[mid]; ,将基准值存储在 pivot 变量中 |
原代码直接使用数组中的元素作为基准值,在后续交换操作中,P[mid] 的值可能会被改变,导致分区逻辑混乱。而修正后代码将基准值单独存储,避免了基准值在交换过程中被意外修改,保证了分区的正确性 |
(二)循环逻辑
对比项目 | 原代码(行19-34) | 修正后代码(行19-34) | 易错点分析 |
---|---|---|---|
内层循环条件 | while(P[i]<P[mid]) 和 while(P[j]>P[mid]) ,未处理元素等于基准值的情况 |
while (P[i] < pivot) 和 while (P[j] > pivot) ,结合外层 if (i <= j) 处理边界情况 |
原代码在处理元素等于基准值时,没有正确的处理逻辑,可能导致 i 和 j 交叉后继续交换,造成无限循环。修正后代码通过合理设置循环条件和外层判断,确保 i 和 j 不会交叉,避免了无限循环问题 |
交换操作 | 交换后直接进行 i++,j-- ,未判断 i 和 j 的位置关系 |
交换后使用 if (i <= j) 判断,只有在 i 和 j 未交叉时才进行指针移动 |
原代码没有对交换后的 i 和 j 位置关系进行判断,可能导致指针越界或错误交换。修正后代码通过判断,保证了指针在正确的范围内移动,避免了错误操作 |
(三)递归调用
对比项目 | 原代码(行36-37) | 修正后代码(行36-37) | 易错点分析 |
---|---|---|---|
递归区间 | quick(P, l, newp); 和 quick(P, newp+1, r); ,newp 的更新逻辑不完整,可能无法正确确定基准值新位置 |
quick(P, l, j); 和 quick(P, i, r); ,根据 i 和 j 的最终位置确定递归区间 |
原代码中 newp 的更新逻辑存在缺陷,当 i 或 j 等于基准值索引时,不能准确更新 newp ,导致递归区间错误。修正后代码根据 i 和 j 的最终位置确定递归区间,保证了每次递归都能正确划分数据,实现快速排序的功能 |
三、完整代码对比
(一)原错误代码
#include<stdio.h>
int n;
int P[100100];
int mid;
int i,j;
int temp, newp;
void quick(int P[100100], int l, int r){
if(l>=r){
return;
}
mid = (l+r)>>1;
i = l, j = r;
newp = -1;
while(i<=j){
while(P[i]<P[mid]){
i++;
}
while(P[j]>P[mid]){
j--;
}
temp = P[i];
P[i] = P[j];
P[j] = temp;
if(i==mid){
newp = j;
}
if(j==mid){
newp = i;
}
i++,j--;
}
quick(P, l, newp);
quick(P, newp+1, r);
}
int main(){
scanf("%d",&n);
for (int i = 0; i < n; i++) scanf("%d", &P[i]);
quick(P, 0, n-1);
for (int i = 0; i < n; i++) printf("%d ", P[i]);
return 0;
}
(二)修正后代码
#include<stdio.h>
int n;
int P[100100];
void quick(int P[], int l, int r) {
if (l >= r) {
return;
}
int mid = (l + r) / 2;
int pivot = P[mid];
int i = l, j = r;
while (i <= j) {
while (P[i] < pivot) {
i++;
}
while (P[j] > pivot) {
j--;
}
if (i <= j) {
int temp = P[i];
P[i] = P[j];
P[j] = temp;
i++;
j--;
}
}
quick(P, l, j);
quick(P, i, r);
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &P[i]);
}
quick(P, 0, n - 1);
for (int i = 0; i < n; i++) {
printf("%d ", P[i]);
}
return 0;
}
四、总结
通过对原错误代码和修正后代码的对比分析,我们可以清晰地看到快速排序算法实现过程中的易错点。在基准值选择与处理上,要避免基准值在交换中被修改;循环逻辑需妥善处理元素等于基准值的情况,防止无限循环;递归调用要准确确定分区边界。理解并规避这些易错点,有助于正确实现快速排序算法,提升编程的准确性和效率。