带有一些规范的c++数组排序
c++ array sorting with some specifications
我使用的是C++。允许使用STL中的排序。
我有一个int数组,如下所示:
1 4 1 5 145 345 14 4
数字存储在字符*中(我从二进制文件中读取,每个数字4个字节)
我想用这个数组做两件事:
将每个号码换成之后的号码
4 1 5 1 345 145 4 14
按2组进行排序
4 1 4 14 5 1 345 145
我可以一步一步地对它进行编码,但效率不高。我想要的是速度。O(n log n)会很棒。
此外,此阵列可能大于500MB,因此内存使用率是个问题。
我的第一个想法是从末尾开始对数组进行排序(将数字2换成2),并将其视为长*(强制每次排序需要2 int)。但我无法对它进行编码,我甚至不确定它是否有效。
我希望我已经足够清楚了,谢谢你的帮助:)
这是我能想到的最节省内存的布局。显然,假设endian-ness处理得足够好,我使用的向量将被您使用的数据blob所取代。下面代码的前提很简单。
-
成对生成1024个随机值,每对由1到500之间的第一个数字和1到50之间的第二个数字组成。
-
对整个列表进行迭代,用下面的奇数索引兄弟翻转所有偶数索引值。
-
将整个内容发送到
std::qsort
,项目宽度为两个(2)int32_t
值,计数为原始向量的一半。 -
比较器函数只是先对立即数进行排序,如果第一个值相等,则对第二个值进行排序。
下面的示例对1024个项目执行此操作。我在没有输出的情况下测试了134217728项(确切地说是536870912字节),结果对于一台微不足道的macbook air笔记本电脑来说非常令人印象深刻,大约15秒,只有实际排序的10秒。理想情况下,最重要的是除了数据向量之外,不需要额外的内存分配是的,对于纯粹主义者来说,我确实使用了调用堆栈空间,但这只是因为q-sort使用了。
我希望你能有所收获。
注意:我只显示输出的第一部分,但我希望它能显示您想要的内容。
#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
#include <cstdint>
// a most-wacked-out random generator. every other call will
// pull from a rand modulo either the first, or second template
// parameter, in alternation.
template<int N,int M>
struct randN
{
int i = 0;
int32_t operator ()()
{
i = (i+1)%2;
return (i ? rand() % N : rand() % M) + 1;
}
};
// compare to integer values by address.
int pair_cmp(const void* arg1, const void* arg2)
{
const int32_t *left = (const int32_t*)arg1;
const int32_t *right = (const int32_t *)arg2;
return (left[0] == right[0]) ? left[1] - right[1] : left[0] - right[0];
}
int main(int argc, char *argv[])
{
// a crapload of int values
static const size_t N = 1024;
// seed rand()
srand((unsigned)time(0));
// get a huge array of random crap from 1..50
vector<int32_t> data;
data.reserve(N);
std::generate_n(back_inserter(data), N, randN<500,50>());
// flip all the values
for (size_t i=0;i<data.size();i+=2)
{
int32_t tmp = data[i];
data[i] = data[i+1];
data[i+1] = tmp;
}
// now sort in pairs. using qsort only because it lends itself
// *very* nicely to performing block-based sorting.
std::qsort(&data[0], data.size()/2, sizeof(data[0])*2, pair_cmp);
cout << "After sorting..." << endl;
std::copy(data.begin(), data.end(), ostream_iterator<int32_t>(cout,"n"));
cout << endl << endl;
return EXIT_SUCCESS;
}
输出
After sorting...
1
69
1
83
1
198
1
343
1
367
2
12
2
30
2
135
2
169
2
185
2
284
2
323
2
325
2
347
2
367
2
373
2
382
2
422
2
492
3
286
3
321
3
364
3
377
3
400
3
418
3
441
4
24
4
97
4
153
4
210
4
224
4
250
4
354
4
356
4
386
4
430
5
14
5
26
5
95
5
145
5
302
5
379
5
435
5
436
5
499
6
67
6
104
6
135
6
164
6
179
6
310
6
321
6
399
6
409
6
425
6
467
6
496
7
18
7
65
7
71
7
84
7
116
7
201
7
242
7
251
7
256
7
324
7
325
7
485
8
52
8
93
8
156
8
193
8
285
8
307
8
410
8
456
8
471
9
27
9
116
9
137
9
143
9
190
9
190
9
293
9
419
9
453
在您的输入和平台上都有一些额外的约束,您可能会使用您正在考虑的方法。这些限制包括
- 您的输入仅包含正数(即可以被视为无符号)
- 您的平台在
<cstdint>
中提供uint8_t
和uint64_t
- 您使用已知的endianness来处理单个平台
在这种情况下,您可以将输入划分为8个字节的组,进行一些字节洗牌,将每组排列为一个uint64_t
,其中输入的"第一个"数字位于值较低的一半,然后在生成的数组上运行std::sort
。根据endianness,您可能需要进行更多的字节洗牌,以按预期顺序将每个排序的8字节组重新排列为一对uint32_t。
如果不能自己编写,我强烈建议您不要采用这种方法。
一种更好、更可移植的方法(从一个没有明确指定的二进制文件格式开始,您会有一些固有的不可移植性)是:
std::vector<int> swap_and_sort_int_pairs(const unsigned char buffer[], size_t buflen) {
const size_t intsz = sizeof(int);
// We have to assume that the binary format in buffer is compatible with our int representation
// we also require an even number of integers
assert(buflen % (2*intsz) == 0);
// load pairwise
std::vector< std::pair<int,int> > pairs;
pairs.reserve(buflen/(2*intsz));
for (const unsigned char* bufp=buffer; bufp<buffer+buflen; bufp+= 2*intsz) {
// It would be better to have a more portable binary -> int conversion
int first_value = *reinterpret_cast<int*>(bufp);
int second_value = *reinterpret_cast<int*>(bufp + intsz);
// swap each pair here
pairs.emplace_back( second_value, firstvalue );
}
// less<pair<..>> does lexicographical ordering, which is what you are looking ofr
std::sort(pairs.begin(), pairs.end());
// convert back to linear vector
std::vector<int> result;
result.reserve(2*pairs.size());
for (auto& entry : pairs) {
result.push_back(entry.first);
result.push_back(entry.second);
}
return result;
}
初始解析/交换过程(无论如何都需要)和最终转换都是O(N),因此总复杂性仍然是(O(N-log(N))。
如果可以继续使用对,则可以保存最终转换。保存转换的另一种方法是使用手工编码的排序,其中包含两个int步进和两个int交换:需要做更多的工作,而且可能仍然很难像经过良好调整的库排序那样高效
一次做一件事。首先,给你的数据一些结构。似乎每个8字节都构成了形成
struct unit {
int key;
int value;
}
如果endianness是正确的,那么可以在O(1)中使用interpret_cast来实现这一点。如果不是,你将不得不忍受O(n)转换的努力。与O(n log n)搜索努力相比,两者都消失了。
当你有一个这些单元的数组时,你可以使用std::sort-like:
bool compare_units(const unit& a, const unit& b) {
return a.key < b.key;
}
std::sort(array, length, compare_units);
这个解决方案的关键是首先进行"交换"和字节解释,然后进行排序。
- 显示错误输出的简单数组排序程序
- C 使用单个函数对具有多种值类型的数组排序
- 2D数组排序,空格打乱顺序
- C 2D数组排序
- C++数组排序 - 将"bbba"和"0001"视为不正确排序的问题
- 数组排序功能
- CString 数组排序
- 简单的数组排序/检查 划分和征服版本
- C++ 中的多维数组排序
- 选择在++中对并行数组排序
- C++:二维指针数组排序:选择排序不适用于某些实例
- C++字符串数组排序
- C++中的指针数组排序算法
- 在VC++6中使用向量进行数组排序时出错,而在VC++2012中没有错误
- 将索引数组排序为主数组
- 数组排序、数组输入、数组输出
- C++数组排序,内存错误
- 在嵌入式系统上将数组排序功能从c++移植到c
- 基于其他int数组排序
- 多维数组排序c++奇怪行为