今天做了一道题,用我原本在书上学的快排只ac40,然后参考了题解对代码进行优化,才过的,感觉优化过后的快排是更加灵活的,嗯又学到了新东西。正好晚上答辩的时候学长问了关于快排复杂度的问题,我没有回答出来。所以去学习了一下:
----------------------------------------------------------------------------------------------三种排序算法的时间复杂度:
桶排:O(M+N)
冒泡排序:O(N^2)
快速排序:O(NlogN)
快排较快的原因:
快熟排序之所以较快,是因为相比冒泡排序,每次交换是跳跃式的,每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样只能在相邻的数之间进行交换,交换的距离就大得多了。因此总的比较和交换次数减少了,速度自然就提高了。当然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和冒泡排序是一样的,都是O(N^2),它平均时间复杂度为O(NlogN)。其实快速排序是基于一种叫做“二分”的思想。
---------------------------------------------------------------------------------------------------------------------------------
回到这道题
题目如下
题目描述
利用快速排序算法将读入的 NN 个数从小到大排序后输出。
快速排序是信息学竞赛的必备算法之一。对于快速排序不是很了解的同学可以自行上网查询相关资料,掌握后独立完成。(C++ 选手请不要试图使用
STL
,虽然你可以使用sort
一遍过,但是你并没有掌握快速排序算法的精髓。)输入格式
第 11 行为一个正整数 NN,第 22 行包含 NN 个空格隔开的正整数 a_iai,为你需要进行排序的数,数据保证了 A_iAi 不超过 10^9109。
输出格式
将给定的 NN 个数从小到大输出,数之间空格隔开,行末换行且无空格。
输入输出样例
输入 #1复制
5 4 2 4 5 1输出 #1复制
1 2 4 4 5说明/提示
对于 20\%20% 的数据,有 N\leq 10^3N≤103;
对于 100\%100% 的数据,有 N\leq 10^5N≤105。
题目标题为模板题,一开始我写的是真的模板(学习快排时书上的方法)。然而时间超限了呜呜。
#include<stdio.h>
int a[1000001],n;//定义全局变量,这两个变量需要在子函数中使用
void quicksort(int left,int right)
{
int i,j,temp,t;
if(left>right)//结束语句
return;
temp=a[left];//temp中存的就是准基数
i=left;
j=right;
while(i!=j)
{
//顺序很重要,基准数为最左边的数,则要先从右往左找
while(a[j]>=temp&&i<j)
j--;
while(a[i]<=temp&&i<j)
i++;
//交换两个数在数组中的位置
if(i<j)//当i和j没有相遇时
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
}
//最终将准基数归位
a[left]=a[i];
a[i]=temp;
//递归处理左右两边数据
quicksort(left,i-1);
quicksort(i+1,right);
}
int main()
{
int i,j,t;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
quicksort(1,n);//调用快速排序
//输出结果
for(i=1;i<=n;i++)
printf("%d ",a[i]);
return 0;
}
ac40,其他数据时间超限。然后修改成这样子才过的,需要注意点都在代码段中注释了。
#include<stdio.h>
int n,a[100000];
void quicksort(int l,int r)
{
int i,j,mid,t;
mid=a[(l+r)/2];//中间数
i=l;j=r;
while(i<=j)//中间数并不是中值
{
while(a[i]<mid) i++;//遇到大于中间数的值则出
while(a[j]>mid) j--;//遇到小于中间数的值则出
if(i<=j)//这个判断不可以省略,因为结果两个while,i和j可能已经不满足i<=j了,但是此时还不会跳出while循环
{
t=a[i];a[i]=a[j];a[j]=t;//交换
i++;j--;
}
}
//出来到这里说明此时i>j
//数据顺序为l.....j.i.....r或j i l...r或l...r j i
//递归处理左右两边数据
if(l<j) quicksort(l,j);
if(i<r) quicksort(i,r);
}
int main()
{
scanf("%d",&n);
//输入序列
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
quicksort(1,n);//快排
//输出序列
for(int i=1; i<=n; i++)
printf("%d ",a[i]);
}
下午进行了测试,只写出三道题,不太满意emmm,后期家里的wifi居然炸了,无语子...不过幸好重启后在最后五分钟恢复了,让我把最后一个写出的题交上去了。
其他时间都在学习c++。(看bilibili上的视频//看来50小节课)做了学习笔记,也有所收获:
(发现c++和c确实区别不大,有点后悔的是早知道当时入门的时候来看b站上c++的讲解视频了,因为基础知识点大部分都是一样的,这样子当时可能就会更顺利了)
噢,另外还看视频学习了位运算,因为之前做题参考题解时,看到有人用<<或者>>这样子的符号的方法,写出来的解题代码很简洁,就去问了学长,才知道这个是位运算,就去学习了一下,也做了相关笔记:
今天新开的题解除了那个快排的题,好像其他都是有关二叉树什么的,所以计划明天一天就看书,把并查集,二叉树的内容看完,学会之后再去写题。
end。