排序
快速选择排序:是一个在平均情况下的时间复杂度为O(nlogn),最坏的时间复杂度为O() ,且是一个不稳定的排序方法,但一般情况下它的排序速度很快,只有当数据基本有序的时候速度是最慢的。
排序的过程:
-
一般选择待排序表中的第一个记录作为基准数,然后初始化两个指针 low 和 high ,分别指向表的上界和下界
- 从表的最右侧开始依次向左搜索,找到第一个关键字小于基准数的记录,将其移到 low 处并high--。
- 接着从表的最左侧位置开始依次向右边搜索,找到第一个大于基准数的记录,将其移到 high 的位置后 low++.
- 重复操作2和3,直至 low 和 high 相等,此时 low 和 high 的位置即为基准数在此序列中的最终位置。
由上面的过程我们可以写出以下的代码:
void quick_sort(int low, int high)
{
if(low < high)
{
//swap(s[low], s[(low + high) / 2]); 有些快速选择排序是将中间的值作为基准数作为排序,这样当数据基本有序的时候可以降低运行时间
int i = low, j = high, x = s[low];
while(i < j)
{
while(i < j && s[j] >= x) //从右往左找第一个小于x的数
j--;
if(i < j) //跟左边的l位置上进行交换
s[i++] = s[j];
while(i < j && s[i] < x) //从左往右找第一个大于或等于x的数
i++;
if(i < j) //同理
s[j--] = s[i];
}
s[i] = x; //注意最后排序好后要将基准数填进去
quick_sort(a, low, i - 1); //递归排序左边的区间
quick_sort(a, i + 1, high); //递归排序右边的区间
}
}
但此时的快排的代码还不够快。。。如果你去做洛谷的P1177就会发现还是会TLE。。。。。
搜了一下题解发现还有另一种写法的快排。。所以下面就来分享一波。。。
这一种方法是从左右两个方向同时进行的快排。。下面就用个例子来解释一下。
从初始序列“6 1 2 7 9 3 4 5 10 8”两端开始“探测”。先从右往左找一个小于6的数,再从左往右找一个大于6的数,然后交换他们。这里可以用两个变量i和j,分别指向序列最左边和最右边。我们为这两个变量起个好听的名字“哨兵i”和“哨兵j”。刚开始的时候让哨兵i指向序列的最左边(即i=1),指向数字6。让哨兵j指向序列的最右边(即j=10),指向数字8。
首先哨兵j开始出动。因为此处设置的基准数是最左边的数,所以需要让哨兵j先出动。哨兵j一步一步地向左挪动(即j--),直到找到一个小于6的数停下来。接下来哨兵i再一步一步向右挪动(即i++),直到找到一个数大于6的数停下来。最后哨兵j停在了数字5面前,哨兵i停在了数字7面前。
现在交换哨兵i和哨兵j所指向的元素的值。交换之后的序列如下:
6 1 2 5 9 3 4 7 10 8
到此,第一次交换结束。接下来开始哨兵j继续向左挪动(再友情提醒,每次必须是哨兵j先出发)。他发现了4(比基准数6要小,满足要求)之后停了下来。哨兵i也继续向右挪动的,他发现了9(比基准数6要大,满足要求)之后停了下来。此时再次进行交换,交换之后的序列如下:
6 1 2 5 4 3 9 7 10 8
第二次交换结束,“探测”继续。哨兵j继续向左挪动,他发现了3(比基准数6要小,满足要求)之后又停了下来。哨兵i继续向右移动,糟啦。此时哨兵i和哨兵j相遇了,哨兵i和哨兵j都走到3面前。说明此时“探测”结束。我们将基准数6和3进行交换。交换之后的序列如下:
3 1 2 5 4 6 9 7 10 8
到此第一轮“探测”真正结束。此时以基准数6为分界点,6左边的数都小于等于6,6右边的数都大于等于6。回顾一下刚才的过程,其实哨兵j的使命就是要找小于基准数的数,而哨兵i的使命就是要找大于基准数的数,直到i和j碰头为止。
代码实现如下:
(注意://此处的m的值的设置是为了使快排更快。前面图的基数设置是为了方便大家理解)
void quick_sort(int l, int r)
{
int i = l, j = r, m = a[(l+r)/2];
while(i <= j)
{
while(a[j] > m)
j--;
while(a[i] < m)
i++;
if(i <= j)
{
swap(a[i], a[j]);
i++;
j--;
}
}
//至此,i > j, l 到 j 部分为小于基准数, i 到 r 部分为大于基准数
if(l < j)
quick_sort(l, j);
if(i < r)
quick_sort(i, r);
}
顺便附上洛谷P1177的AC代码:
#include <iOStream>
#include <algorithm>
using namespace std;
int a[100005];
void quick_sort(int l, int r)
{
int i = l, j = r, m = a[(l+r)/2];
while(i <= j)
{
while(a[j] > m)
j--;
while(a[i] < m)
i++;
if(i <= j)
{
swap(a[i], a[j]);
i++;
j--;
}
}
if(l < j)
quick_sort(l, j);
if(i < r)
quick_sort(i, r);
}
int main()
{
int n;
while(cin >> n)
{
for(int i = 0; i < n; i++)
cin >> a[i];
quick_sort(0, n - 1);
for(int i = 0; i < n; i++)
{
cout << a[i];
if(i != n - 1)
cout << " ";
}
cout << endl;
}
return 0;
}
参考链接:https://yq.aliyun.com/ziliao/353024 https://blog.csdn.net/morewindows/article/details/6684558
相关阅读
据我所知,现在互联网上的草根站长,大多数都是靠搜索引擎吃饭,所以站长们就不断利用各种手段来讨好搜索蜘蛛,乞求有朝一日能一柱擎天飙
第01课:高效学习方程式,你的学习到底是哪里出了问题一、学习不好的原因高效学习的方程式,最终的学习效果=时间*精力*注意力*目标*策
A5创业网(公众号:iadmin5)3月3日报道,索尼正式结束便携式游戏机PlayStation Vita的生产,剩余的的两个型号现在该设备的官方产品页面上
直通车思维并不是指直通车操作,而是怎么去更好的选择,我在哪个时期要花多少钱,哪个时期要选择广泛还是人群,多高的投产要提高流量。不
对于喜欢逛CSDN的人来说,看别人的博客确实能够对自己有不小的提