您的位置:首页 > 编程语言 > C语言/C++

c++实现快速选择算法

2017-01-17 18:20 267 查看
在给定的一串序列中,选择出第k大/小的元素。

根据快速排序算法,给出一种解决方案,优点就是只对局部的一部分排序。相比与快速排序算法,快速选择是进行一次递归调用。平均时间为O(N)。

程序如下,给出了快速排序算法的结果进行对比:

#include<iostream>
#include<vector>
#include<random>
#include<ctime>
#include<iterator>
#include<algorithm>
using namespace std;

/*
* 快速排序通过递归实现,因此该函数为驱动函数
*/
template<typename Comparable>
void quickSort(vector<Comparable> & a)
{
quickSort(a, 0, a.size() - 1);
}

/*
* 通过“三数选中”的方法选择枢纽元
* 找到枢纽元后,放在right-1的位置上
*/
template<typename Comparable>
const Comparable & median3(vector<Comparable> &a, int left, int right)
{
//从对left,center,right位置上的三个数进行排序
int center = (left + right) / 2;
if (a[center] < a[left])
swap(a[left], a[center]);
if (a[right] < a[left])
swap(a[right], a[left]);
if (a[right] < a[center])
swap(a[right], a[center]);

//此时left、center、right位置上的数从小到大排序,且center位置上的元素为枢纽元
//现在把center上的枢纽元放在right-1 的位置上
swap(a[center], a[right - 1]);

return a[right - 1];

}
/*
快速排序主要的函数
a表示待排的向量
left表示子序列的最左边元素下标
right表示子序列的最右边元素的下标
*/
template<typename Comparable>
void quickSort(vector<Comparable> & a, int left, int right)
{
if (left + 10 < right)
{
Comparable pivot = median3(a, left, right);
int i = left;
int j = right - 1;
while (1)
{
while (a[++i] < pivot);
while (a[--j] > pivot);
//因为如果i和j遇到等于枢纽元的元素,就让i和j都停止
if (i < j)
swap(a[i], a[j]);
else
break;
}
swap(a[i], a[right - 1]);//把枢纽元放回在相应的位置
quickSort(a, left, i - 1);//把小于枢纽元的集合排序
quickSort(a, i + 1, right);//把大于枢纽元的集合排序
}
else
{
insertionSort(a, left, right);
}

}

/*
* 快速选择通过递归实现,因此该函数为驱动函数
*/
template<typename Comparable>
const Comparable & quickSelect(vector<Comparable> & a, int k)
{
if (a.size() < k)
{
cout << "选取元素应该小于待选取序列的元素个数!" << endl;
exit(-1);
}
quickSelect(a, 0, a.size() - 1, k);
return a[k - 1]; //第k大的元素在k-1的位置上,因为序列下标从0开始
}

/*
快速排序主要的函数
a表示待排的向量
left表示子序列的最左边元素下标
right表示子序列的最右边元素的下标
*/
template<typename Comparable>
void quickSelect(vector<Comparable> & a, int left, int right, int k)
{
if (left + 10 < right)
{
Comparable pivot = median3(a, left, right);
int i = left;
int j = right - 1;
while (1)
{
while (a[++i] < pivot);
while (a[--j] > pivot);
//因为如果i和j遇到等于枢纽元的元素,就让i和j都停止
if (i < j)
swap(a[i], a[j]);
else
break;
}
swap(a[i], a[right - 1]);//把枢纽元放回在相应的位置
if (k<=i)
quickSelect(a, left, i - 1, k);//如果k小于等于i的位置,则在左半部分
else
quickSelect(a, i + 1, right, k);//负责在右半部分
}
else
{
insertionSort(a, left, right);
}

}

/*
在快速排序递归的时候,如果向量长度小于10就用插入排序
*/
template<typename Comparable>
void insertionSort(vector<Comparable> & a, int left, int right)
{
for (int p = left + 1; p <= right; ++p) // 从第二个数开始
{
Comparable tmp = a[p];
int j = p;
for (; j > left && a[j - 1] > tmp; --j)
a[j] = a[j - 1];
a[j] = tmp;
}
}

/*输出向量*/
template<typename T>
void printVector(vector<T> & v)
{
copy(v.cbegin(), v.cend(), ostream_iterator<T>(cout, " "));
cout << endl;
}

int main()
{
vector<int> source;
uniform_int_distribution<int> u(0, 100);
default_random_engine e(static_cast<unsigned int>(time(0)));
for (int i = 0; i < 31; i++)
{
source.push_back(u(e));
}

cout << "原始序列:" << endl;
printVector(source);

vector<int> source1(source);
vector<int> source2(source);

quickSort(source1);

cout << "排序后:" << endl;
printVector(source1);

int k = 10;
cout << "第" << k << "小的元素是" << quickSelect(source2, k) << endl;

cout << "第" << k << "小的元素后,序列为" << endl;
printVector(source2);

return 0;
}

结果为:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐