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;
}
结果为:
根据快速排序算法,给出一种解决方案,优点就是只对局部的一部分排序。相比与快速排序算法,快速选择是进行一次递归调用。平均时间为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;
}
结果为:
相关文章推荐
- c++实现快速选择算法
- 快速选择算法 C++实现
- [分治]快速选择算法 C++实现
- 几种常用的排序算法:插入排序、冒泡排序、选择排序的算法及C++实现
- 基本算法简单实现-二分法查找、合并排序、冒泡排序、插入排序、选择排序、快速排序
- Fast Compressive Tracking(快速压缩跟踪)算法的C++代码实现
- 算法代码实现之选择排序,C/C++ 实现
- 插入排序、冒泡排序、选择排序、希尔排序、快速排序、归并排序、堆排序和LST基数排序——C++实现
- 快速选择算法的一个简单实现
- 常见排序算法(冒泡、选择、插入、快速、归并C++实现)
- 算法学习 - 快速幂和矩阵快速幂(复杂度Olog(n))C++实现
- 常用排序算法的c++实现(冒泡,选择,插入,堆,shell,快速,归并 )与sort()对比
- Fast Compressive Tracking(快速压缩跟踪)算法的C++代码实现
- C++实现Chi-square 特征词选择算法
- 算法学习 - 选择排序的稳定性讨论(C++实现)
- 常用排序算法的c++实现(冒泡,选择,插入,堆,shell,快速,归并 )与sort()对比 - coder_xia的专栏 - 博客频道 - CSDN.NET
- 用objective-c 实现常用算法(冒泡、选择、快速、插入)
- 笔试算法题(56):快速排序实现之非递归实现,最小k值选择(non-recursive version, Minimal Kth Selection of Quick Sort)
- objective-c 实现常用算法(冒泡、选择、快速、插入)
- 冒泡排序、选择排序、堆排序、快速排序、插入排序算法复杂度分析与算法实现(自己总结与转)