在M个已知数中求N个最大数的程序

bitma 2008-05-27 02:05:54
M=2000
n=200
请给出一个效率比较高的程序?谢谢!
...全文
251 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
grellen 2008-05-27
  • 打赏
  • 举报
回复
mark
hopeclass_shych 2008-05-27
  • 打赏
  • 举报
回复
要考虑正负号不?
laolaoliu2002 2008-05-27
  • 打赏
  • 举报
回复
nth_element是STL提供的一个算法,用于找出序列中的第n大元素。这个算法涉及下面4个辅助函数:

_Nth_element
_Unguarded_partition
_Median
_Med3
下面是我对STL源代码的注释。

/********************************************************************************************
_Nth_element

使序列中第n大的元素位于第n个位子上,使用 < 比较元素。
基本思想:
(1) 找到一个包含n的足够小的区间[a,b),使得[a,b)作为一个大粒度的元素处于序列的有序位置。
(2) 对[a,b)部分进行排序。
nth_element查找区间的方式体现了二分(折半)查找的思想。它的核心是ungarded_partition算法,ungarded_partition算法能够找出随机序列的近似的位置中间值。
*********************************************************************************************/
template<class _RanIt> inline
void _Nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last)
{ // order Nth element, using operator<
_DEBUG_RANGE(_First, _Last);

/* 逐步缩小[_First, _Last)的区间,直至尺寸小到可以直接对局部进行排序。
_ISORT_MAX 是一个阀值,在<algorithm>中被定义为32,表示适于插入法排序的序列的最大长度。*/
for (; _ISORT_MAX < _Last - _First; )
{ // divide and conquer, ordering partition containing Nth

/* 把序列的当前部分划分为有序的三份。*/
pair<_RanIt, _RanIt> _Mid =
_Unguarded_partition(_First, _Last);

/* 确定下一步搜索区间。*/
if (_Mid.second <= _Nth)
_First = _Mid.second;
else if (_Mid.first <= _Nth)
return; // Nth inside fat pivot, done
else
_Last = _Mid.first;
}

/* 对[_First, _Last)排序,第n大元素就到了第n个位置上。*/
_Insertion_sort(_First, _Last); // sort any remainder
}

/********************************************************************************************
_Unguarded_partition

把序列划分为有序的三份:[_First, Mid.First), [Mid.First, Mid.Second), [Mid.Second, _Last),其中[Mid.First, Mid.Second)内的元素相等。
注意,不是等分:
(1) 不保证[Mid.First, Mid.Second)在位置上处于序列的中间。
(2) 不保证[Mid.First, Mid.Second)在元素值上处于序列的中间。
(3) [_First, Mid.First)和[Mid.Second, _Last)的长度有可能为0。
(4) [_First, Mid.First)中的所有元素(若有)小于[Mid.First, Mid.Second)中的任一元素。[Mid.Second, _Last)中的则大于。
********************************************************************************************/
template<class _RanIt> inline
pair<_RanIt, _RanIt> _Unguarded_partition(_RanIt _First, _RanIt _Last)
{ // partition [_First, _Last), using operator<
_RanIt _Mid = _First + (_Last - _First) / 2; // sort median to _Mid

/* 选择序列的位置平均值(近似),作为枢轴值(pivot)。*/
_Median(_First, _Mid, _Last - 1);

/* [_Pfirst, _Plast) 就是要找的区间。*/
_RanIt _Pfirst = _Mid;
_RanIt _Plast = _Pfirst + 1;

/* 以枢轴值为起点,向序列的两头扫描,把相邻的与枢轴值相等的元素合并到[_Pfirst, _Plast)中。
宏 _DEBUG_LT(x,y) 定义为 ((x)<(y))。
值得注意的是,下面的代码用两次 < 比较实现 == 比较。*/
while (_First < _Pfirst
&& !_DEBUG_LT(*(_Pfirst - 1), *_Pfirst)
&& !(*_Pfirst < *(_Pfirst - 1)))
--_Pfirst;
while (_Plast < _Last
&& !_DEBUG_LT(*_Plast, *_Pfirst)
&& !(*_Pfirst < *_Plast))
++_Plast;

/* 分别以[_Pfirst, _Plast)的起、止位置为起点,向序列的两头扫描。*/

_RanIt _Gfirst = _Plast;
_RanIt _Glast = _Pfirst;

for (; ; )
{ // partition
for (; _Gfirst < _Last; ++_Gfirst)
if (_DEBUG_LT(*_Pfirst, *_Gfirst))
;
else if (*_Gfirst < *_Pfirst)
break;
else
std::iter_swap(_Plast++, _Gfirst);
/* 除非 _Gfirst == _Last,否则 *_Gfirst 应该调到[_Pfirst, _Plast)的前面。*/

for (; _First < _Glast; --_Glast)
if (_DEBUG_LT(*(_Glast - 1), *_Pfirst))
;
else if (*_Pfirst < *(_Glast - 1))
break;
else
std::iter_swap(--_Pfirst, _Glast - 1);
/* 除非 _Glast == _First,否则 *(_Glast-1) 应该调到[_Pfirst, _Plast)的后面。*/

if (_Glast == _First && _Gfirst == _Last)
return (pair<_RanIt, _RanIt>(_Pfirst, _Plast));

/* 如果 *_Gfirst 和 *(_Glast-1) 都需要调到[_Pfirst, _Plast)的对面,交换它俩就行了。
如果只有其中一个(记为G)要调整,那就交换它和[_Pfirst, _Plast)——实际上要复杂些,有两种情况:
(1) G与[_Pfirst, _Plast)相邻。这时只需要交换G和其对面的区间边界。
(2) G与[_Pfirst, _Plast)之间有其它元素。这时需要三方交换(两次):第一次交换使枢轴区间移动一个单位(通过交换区间的内部边界和对面的外部边界来实现),第二次交换完成调整任务。*/
if (_Glast == _First)
{ // no room at bottom, rotate pivot upward
if (_Plast != _Gfirst)
std::iter_swap(_Pfirst, _Plast);
++_Plast;
std::iter_swap(_Pfirst++, _Gfirst++);
}
else if (_Gfirst == _Last)
{ // no room at top, rotate pivot downward
if (--_Glast != --_Pfirst)
std::iter_swap(_Glast, _Pfirst);
std::iter_swap(_Pfirst, --_Plast);
}
else
std::iter_swap(_Gfirst++, --_Glast);
}
}

/*******************************************************************************************
_Median

找序列的近似位置平均值。
********************************************************************************************/
template<class _RanIt> inline
void _Median(_RanIt _First, _RanIt _Mid, _RanIt _Last)
{ // sort median element to middle
if (40 < _Last - _First)
{ // median of nine
size_t _Step = (_Last - _First + 1) / 8;
_Med3(_First, _First + _Step, _First + 2 * _Step);
_Med3(_Mid - _Step, _Mid, _Mid + _Step);
_Med3(_Last - 2 * _Step, _Last - _Step, _Last);
_Med3(_First + _Step, _Mid, _Last - _Step);
}
else
_Med3(_First, _Mid, _Last);
}

/********************************************************************************************
_Med3

对三个元素排序。
********************************************************************************************/
template<class _RanIt> inline
void _Med3(_RanIt _First, _RanIt _Mid, _RanIt _Last)
{ // sort median of three elements to middle
if (_DEBUG_LT(*_Mid, *_First))
std::iter_swap(_Mid, _First);
if (_DEBUG_LT(*_Last, *_Mid))
std::iter_swap(_Last, _Mid);
if (_DEBUG_LT(*_Mid, *_First))
std::iter_swap(_Mid, _First);
}
matrixdwy 2008-05-27
  • 打赏
  • 举报
回复
排序找?
simo110 2008-05-27
  • 打赏
  • 举报
回复
下面是一次执行结果,因为使用随机算法,所以前面的排序前的数据不一定是下面的这个

排序前的数据(前200个)
686 309 1392 746 1049 348 1813 1841 637 1693 320 1612 1033 1723 1578 1291 1760 1386 1212 462 1883 1881 834 315 1721 7 1742 472 977 1273 402 1616 1710 155 1226 39 1857 850 1624 1786 1778 1288 471 1102 1738 1562 506 1383 1803 1078 198 346 1461 1890 197 582 1111 1398 939 1957 1829 317 1311 1136 295 95 1713 1996 1077 381 1090 893 163 1467 251 1548 1278 1079 1900 1254 1657 1570 1283 773 272 1385 1317 207 1837 1189 1746 796 484 1199 523 434 116 1408 1134 464 1579 16 1515 615 1761 1568 432 812 1451 221 998 675 589 1660 371 1927 1065 1607 358 1819 302 1050 1170 1577 1267 355 559 118 1388 1866 1637 1322 187 533 544 1945 232 166 267 1948 774 780 528 352 214 571 69 1539 1041 1293 1641 1372 690 1151 503 1396 548 807 35 1479 880 981 610 1313 1429 542 986 233 1369 1800 1602 8 1500 912 1482 1076 1068 1139 614 1162 1913 1935 1401 1635 534 1465 276 1877 562 1423 1225 909 948 325 1152 837 438 421 1501 488

排序后的数据(前200个)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
simo110 2008-05-27
  • 打赏
  • 举报
回复

/********************************************************************
created: 2008/05/27
created: 27:5:2008 10:43
filename: f:\coding\CSDN_PartionSort\CSDN_PartionSort\PationSort.cpp
file path: f:\coding\CSDN_PartionSort\CSDN_PartionSort
file base: PationSort
file ext: cpp
author: hecan

purpose: partion sort
*********************************************************************/

///////////////vs2003.net + winXP sp2 pass/////////////////////////////
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

class CGenerate
{
public:
CGenerate(int iInitial = 0):iCount(iInitial)
{
}

int operator() ()
{
return iCount++;
}
protected:
private:
int iCount;
};

int main()
{
vector<int> viData;
const int ciM = 2000;
const int ciN = 200;

generate_n(back_inserter(viData), ciM, CGenerate());
random_shuffle(viData.begin(), viData.end());

copy(viData.begin(),
viData.begin() + (vector<int>::size_type)ciN,
ostream_iterator<int>(cout, " "));
cout << endl;

partial_sort(viData.begin(),
viData.begin() + (vector<int>::size_type)ciN,
viData.end());

copy(viData.begin(),
viData.begin() + (vector<int>::size_type)ciN,
ostream_iterator<int>(cout, " "));
cout << endl;

}
taodm 2008-05-27
  • 打赏
  • 举报
回复
C++ STL nth_element泛型算法,现成的。
WingForce 2008-05-27
  • 打赏
  • 举报
回复
就叫快速选择:
前几天好像还有人在讨论,虽然是求最小的n个数。。。
http://topic.csdn.net/u/20080503/14/41a8dacd-955d-4020-940a-683830ab0897.html
http://topic.csdn.net/u/20080503/14/41a8dacd-955d-4020-940a-683830ab0897.html
blooney 2008-05-27
  • 打赏
  • 举报
回复
算法导论上面有,类似于快速排序的方式能找到最大的K个数
damo_xu 2008-05-27
  • 打赏
  • 举报
回复
才2000个数,用选择法就行。

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧