由买买提看人间百态

boards

本页内容为未名空间相应帖子的节选和存档,一周内的贴子最多显示50字,超过一周显示500字 访问原贴
Programming版 - 求教:多个有序数组怎么合并最快?
相关主题
N个数字里面找出最大的5个数字的复杂度是什么?O(N)?关于那个经典的missing number的题 (转载)
请问heap sort 数组时数组用preorder顺序存储怎么实现?从王垠的代码看似乎其没在正规公司呆过
如何将若干已升序排序好的数组合并在一起,并仍然是升序?linux 下从c++动态内存操作问题,heap size不够还是别的?
[合集] 一个已经排序好的数组,就是一个堆heap吗?Java数组怎么样能参数传递 (转载)
哪位大侠给说说 何时用 merge sort, 何时用 quick sort, 何时弱问内存的问题
一个查找算法题这二个在C++中有区别不?
请教一个组合的算法一个关于methodology的问题
问高手一个PERL的简单程序[合集] 很无聊的做了两道code jam
相关话题的讨论汇总
话题: 数组话题: heap话题: merge话题: pair话题: 合并
进入Programming版参与讨论
1 (共1页)
x*****g
发帖数: 3463
1
多个有序数组合并成一个有序数组。各数组长度不同。所有数组的所有元素都是唯一的。
就是说,任何数组中的任何元素与任何其他数组中的任何元素都不会相同。
另外,如果每个元素还带有一个属性,要随着元素移动,怎么办?建个结构?
有没有更好的办法?
谢谢!
q****x
发帖数: 7404
2
heap

的。

【在 x*****g 的大作中提到】
: 多个有序数组合并成一个有序数组。各数组长度不同。所有数组的所有元素都是唯一的。
: 就是说,任何数组中的任何元素与任何其他数组中的任何元素都不会相同。
: 另外,如果每个元素还带有一个属性,要随着元素移动,怎么办?建个结构?
: 有没有更好的办法?
: 谢谢!

P********e
发帖数: 2610
3
看你最终有另外output数组还是没有?
有就 正序,否则反序。区别不大。然后,每2个数组合。
多属性没什么不同,就是自建struct, 多个比较函数。
不想写,就用stl的pair.反正都是唯一。

的。

【在 x*****g 的大作中提到】
: 多个有序数组合并成一个有序数组。各数组长度不同。所有数组的所有元素都是唯一的。
: 就是说,任何数组中的任何元素与任何其他数组中的任何元素都不会相同。
: 另外,如果每个元素还带有一个属性,要随着元素移动,怎么办?建个结构?
: 有没有更好的办法?
: 谢谢!

g*****g
发帖数: 34805
4
Merge sort, to be exact, the merge step of it.

的。

【在 x*****g 的大作中提到】
: 多个有序数组合并成一个有序数组。各数组长度不同。所有数组的所有元素都是唯一的。
: 就是说,任何数组中的任何元素与任何其他数组中的任何元素都不会相同。
: 另外,如果每个元素还带有一个属性,要随着元素移动,怎么办?建个结构?
: 有没有更好的办法?
: 谢谢!

f*******a
发帖数: 663
5
一点思路,抛砖引玉
对于N个有序数组,建立一个临时的大小为N的数组,从每个数组里取第一个元素,排序
后放入。
如下循环:
从临时数组中pop第一个元素输出,同时从原所属数组中取下一个元素,排序后放
入临时数组
f*******a
发帖数: 663
6
不矛盾啊,呵呵。
临时数组的变化如下:
[1 6 11]
[2 6 11]
...
[5 6 11]
刚才数组长度不一致忘说了,结束了就置一个NULL或者减少临时数组长度都可以
[6 11]
[7 11]
...
[10 11]
只剩一个的时候直接导入即可
[11]
基本思路而已,运算量不大。欢迎讨论
a***y
发帖数: 2803
7
恩.不错.

【在 f*******a 的大作中提到】
: 不矛盾啊,呵呵。
: 临时数组的变化如下:
: [1 6 11]
: [2 6 11]
: ...
: [5 6 11]
: 刚才数组长度不一致忘说了,结束了就置一个NULL或者减少临时数组长度都可以
: [6 11]
: [7 11]
: ...

f*******a
发帖数: 663
8
整体型的处理思路,很有意思。简而言之,不断的把单个数组插入至待输出的数组中。
个人感觉:随着数组数量的增加,这种算法的效率会随着长度的增加而降低。
另:关于我的算法的比较次数,好像有点问题。满打满算,15个元素,每次进入临时数
组,比较的就3个元素,只要比两次,最大15×2+第一次排序时的比较,不会超过40.如
果考虑数组被清空以及最后一个数组的情况,比较次数会更少。大致估计,这个算法的
运算量是O(logN * 总元素量)
~~~~有序插入

比较;

【在 a***y 的大作中提到】
: 恩.不错.
f*******a
发帖数: 663
9
我理解你的想法,但反之未必
我的算法很简单,你把那个例子的过程全列一遍也不用2分钟。做算法,思维要开放和
大气一些
a******8
发帖数: 660
10
goodbug 不是已经说了用 merge sort 的 merging step 了么?
复杂度对已经有序的数组是各数组长度之和
相关主题
一个查找算法题关于那个经典的missing number的题 (转载)
请教一个组合的算法从王垠的代码看似乎其没在正规公司呆过
问高手一个PERL的简单程序linux 下从c++动态内存操作问题,heap size不够还是别的?
进入Programming版参与讨论
f*******a
发帖数: 663
11
看来偶这样的非专业人士还是对related work不了解啊,呵呵
看了一下,受教了,thanks

【在 a******8 的大作中提到】
: goodbug 不是已经说了用 merge sort 的 merging step 了么?
: 复杂度对已经有序的数组是各数组长度之和

p***o
发帖数: 1252
12
其实你的想法是对的,结合一下2楼提到的heap就好,更多的讨论找Knuth的第二本书看,
比bbs上的讨论靠谱多了 ...

【在 f*******a 的大作中提到】
: 看来偶这样的非专业人士还是对related work不了解啊,呵呵
: 看了一下,受教了,thanks

M**u
发帖数: 10158
13
Knuth的书。。。真不是人看的。。。

看,

【在 p***o 的大作中提到】
: 其实你的想法是对的,结合一下2楼提到的heap就好,更多的讨论找Knuth的第二本书看,
: 比bbs上的讨论靠谱多了 ...

p***o
发帖数: 1252
14
用heap,每个数组顺序读一遍,结果写一遍,从I/O上讲效率已经不错了。
再想提高的话花点时间读文献也是值得的。

【在 M**u 的大作中提到】
: Knuth的书。。。真不是人看的。。。
:
: 看,

g*****g
发帖数: 34805
15
应该说是O(M LogN),M是所有数组长度之和,N是数组的个数。
如果数据在某个已知范围,可以用radix sort进行优化。

【在 a******8 的大作中提到】
: goodbug 不是已经说了用 merge sort 的 merging step 了么?
: 复杂度对已经有序的数组是各数组长度之和

r****o
发帖数: 1950
16
Merge+binary search

【在 g*****g 的大作中提到】
: 应该说是O(M LogN),M是所有数组长度之和,N是数组的个数。
: 如果数据在某个已知范围,可以用radix sort进行优化。

c****p
发帖数: 6474
17
把每个数组的第一个元素放进一个heap,每次heap弹出一个元素就把该元素所在的数组
的第一个元素压入heap

的。

【在 x*****g 的大作中提到】
: 多个有序数组合并成一个有序数组。各数组长度不同。所有数组的所有元素都是唯一的。
: 就是说,任何数组中的任何元素与任何其他数组中的任何元素都不会相同。
: 另外,如果每个元素还带有一个属性,要随着元素移动,怎么办?建个结构?
: 有没有更好的办法?
: 谢谢!

I******c
发帖数: 163
18
两两合并应该比所有数列一起合并要好。合并的时候只要比较就可以了。另外一种思路
是用求rank来合并。看楼上有人提出heap. 我的另外一个想法就是分别建heap, 然后合
并heap. 这里的heap可能用Fibonacci Heaps比较好。
以上的想法是基于顺序的算法。 如果考虑到并行算法可能还有些小技巧可以使用,比
如先分小区间再合并,或者多路查找。
g*****g
发帖数: 34805
19
两两合并是O(NM)的算法,基于堆的合并是O(logN*M)的算法

【在 I******c 的大作中提到】
: 两两合并应该比所有数列一起合并要好。合并的时候只要比较就可以了。另外一种思路
: 是用求rank来合并。看楼上有人提出heap. 我的另外一个想法就是分别建heap, 然后合
: 并heap. 这里的heap可能用Fibonacci Heaps比较好。
: 以上的想法是基于顺序的算法。 如果考虑到并行算法可能还有些小技巧可以使用,比
: 如先分小区间再合并,或者多路查找。

P********e
发帖数: 2610
20
我没看错把。

【在 g*****g 的大作中提到】
: 两两合并是O(NM)的算法,基于堆的合并是O(logN*M)的算法
相关主题
Java数组怎么样能参数传递 (转载)一个关于methodology的问题
弱问内存的问题[合集] 很无聊的做了两道code jam
这二个在C++中有区别不?一道MS面试题 (转载)
进入Programming版参与讨论
I******c
发帖数: 163
21
假设有N个数列,每个数列的元素个数是M. 那么两个数列合并的时间复杂度是O(M),这
种合并需要进行(N/2+N/4+N/8...+1)=N次。所以总的时间复杂度是O(MN)
对于堆合并,如果使用binary heap的话,建堆需要N*O(M). 合并需要O(M)*N。所以总
的时间复杂度是O(MN)
如果使用Binomial heap的话,我不太确认建堆的时间复杂度,合并需要O(lgM)*N
还可以使用fibonacci heap, 不过时间复杂度用的是amortised, 不好比较。
使用Binomial heap和fibonacci heap实现的话可能需要额外空间。

【在 g*****g 的大作中提到】
: 两两合并是O(NM)的算法,基于堆的合并是O(logN*M)的算法
t****t
发帖数: 6806
22
ft, you both counted wrong.
if you do pair-wise merge, suppose every vector has M elements, then first
level you have N/2*M*2=NM. then each level the vector length doubles while
the number of vector halves. so it's still NM. Now you have to merge logN
levels. so it's NMlogN.
if you merge N vectors with a heap of N, then you need to do re-adjust the
help for NM times, each time the complexity is logN. So it's still NMlogN.
goodbug used a different notation: the total number of elements is N and M
vectors. but the complexity calculation remains the same.

【在 I******c 的大作中提到】
: 假设有N个数列,每个数列的元素个数是M. 那么两个数列合并的时间复杂度是O(M),这
: 种合并需要进行(N/2+N/4+N/8...+1)=N次。所以总的时间复杂度是O(MN)
: 对于堆合并,如果使用binary heap的话,建堆需要N*O(M). 合并需要O(M)*N。所以总
: 的时间复杂度是O(MN)
: 如果使用Binomial heap的话,我不太确认建堆的时间复杂度,合并需要O(lgM)*N
: 还可以使用fibonacci heap, 不过时间复杂度用的是amortised, 不好比较。
: 使用Binomial heap和fibonacci heap实现的话可能需要额外空间。

P********e
发帖数: 2610
23
每个数列元素个数不确定。题目没说。
按照好虫虫的m, n表示方法一共有logM层合并,每层合并都是N次comparison.
所以,两两合应该是O ( N * logM )
heap的话。每次push, pop都是logM的复杂度,一共需要N次,所以是
O ( N * logM ).
他们都只是在说worst case running time。空间是另外的话题。

【在 I******c 的大作中提到】
: 假设有N个数列,每个数列的元素个数是M. 那么两个数列合并的时间复杂度是O(M),这
: 种合并需要进行(N/2+N/4+N/8...+1)=N次。所以总的时间复杂度是O(MN)
: 对于堆合并,如果使用binary heap的话,建堆需要N*O(M). 合并需要O(M)*N。所以总
: 的时间复杂度是O(MN)
: 如果使用Binomial heap的话,我不太确认建堆的时间复杂度,合并需要O(lgM)*N
: 还可以使用fibonacci heap, 不过时间复杂度用的是amortised, 不好比较。
: 使用Binomial heap和fibonacci heap实现的话可能需要额外空间。

g*****g
发帖数: 34805
24
错了,你的数列后面越来越大,不是M个数,而是O(MN)个数,最后是O(N^2 M)
如果所有数列所有元素的总数是M。那么是O(NM),而基于堆是O(logN M)

【在 I******c 的大作中提到】
: 假设有N个数列,每个数列的元素个数是M. 那么两个数列合并的时间复杂度是O(M),这
: 种合并需要进行(N/2+N/4+N/8...+1)=N次。所以总的时间复杂度是O(MN)
: 对于堆合并,如果使用binary heap的话,建堆需要N*O(M). 合并需要O(M)*N。所以总
: 的时间复杂度是O(MN)
: 如果使用Binomial heap的话,我不太确认建堆的时间复杂度,合并需要O(lgM)*N
: 还可以使用fibonacci heap, 不过时间复杂度用的是amortised, 不好比较。
: 使用Binomial heap和fibonacci heap实现的话可能需要额外空间。

i**********e
发帖数: 1145
25
写了一个,如果是 k 个数组,每个数组长度最多是 N 的话,那么时间复杂度就是 O(
kN Log (k) )。需要空间复杂度 O(k) 来暂时储存暂时的 indices,来记录每个数组已
经进行到哪里了。
这个也可以用 divide and conquer,每次分半合并,递归解决。虽然时间复杂度是一
样的,但实际上肯定没有用 heap 快,因为递归的关系。
另一个变种就是 merge k sorted linked list,返回一个新的链表。这个就不需要额
外空间,可以每个 list 直接 advanced,指向每个链表进行的位置。但是编写起来很
麻烦,如果你不懂得点技巧的话。这个在 C++ 里用 double dereferencing pointer
代码可以写得相当简洁。
typedef pair Pair;
vector mergeKSortedArrays(vector > A) {
int k = A.size();
priority_queue, greater > q;
vector ret;
int *index = new int[k];

for (int i = 0; i < k; i++) {
q.push(Pair(A[i][0], i));
index[i] = 1;
}
while (!q.empty()) {
Pair p = q.top();
q.pop();
ret.push_back(p.first);
if (index[p.second] < A[p.second].size()) {
q.push(Pair(A[p.second][index[p.second]], p.second));
index[p.second]++;
}
}
delete[] index;
return ret;
}
t****t
发帖数: 6806
26
我说了你们俩都没算对...

【在 g*****g 的大作中提到】
: 错了,你的数列后面越来越大,不是M个数,而是O(MN)个数,最后是O(N^2 M)
: 如果所有数列所有元素的总数是M。那么是O(NM),而基于堆是O(logN M)

g*****g
发帖数: 34805
27
haha, 你说的对。不过用头顶的堆是经典的外排算法,按你那么做
要倒磁带。

【在 t****t 的大作中提到】
: 我说了你们俩都没算对...
t****t
发帖数: 6806
28
我什么也没做...他两两合并的算法虽然IO比较多, 但胜在可并行. 这就比较强大了.

【在 g*****g 的大作中提到】
: haha, 你说的对。不过用头顶的堆是经典的外排算法,按你那么做
: 要倒磁带。

g*****g
发帖数: 34805
29
如果外排的话,假定速度由IO而不是比较决定。一个IO是MN一个是
LogN * MN,就算你上N/2个机器也就能达到LogN的并行度,也只能达到
一个机器的速度而已。必须内排才有用。

【在 t****t 的大作中提到】
: 我什么也没做...他两两合并的算法虽然IO比较多, 但胜在可并行. 这就比较强大了.
I******c
发帖数: 163
30
IO的读取是以块为单位,这个对于堆会有影响。除非在堆里每个节点包含多个数据。

【在 g*****g 的大作中提到】
: 如果外排的话,假定速度由IO而不是比较决定。一个IO是MN一个是
: LogN * MN,就算你上N/2个机器也就能达到LogN的并行度,也只能达到
: 一个机器的速度而已。必须内排才有用。

相关主题
C里面的延时函数请问heap sort 数组时数组用preorder顺序存储怎么实现?
问一个随机排列的问题.如何将若干已升序排序好的数组合并在一起,并仍然是升序?
N个数字里面找出最大的5个数字的复杂度是什么?O(N)?[合集] 一个已经排序好的数组,就是一个堆heap吗?
进入Programming版参与讨论
w***g
发帖数: 5958
31
楼上说的都好,我来总结以下吧。
1. 如果每个数组只允许顺序操作的话,那用heap在复杂度上来说是最低的。
2. 如果是面试题,显然要考虑外排序的情况。这时候就要考虑block size和K的优化。
在外拍情况下每次需要从数组读取一整个block, 用完了再读一整个。 这样内存中最多
可能同时存在K个block。 block size = mem size / K。这个如果太小了就不能发挥顺
序读取的优势。 这时候就得merge sort了。 比如有8GB内存,K = 10000,那么每个
block也就0.8MB。这样显然不能发挥顺序读取的优势。这时候就可以进行100路merge排
序。这样虽然每块数据要多读写一次,但是block size变成了80MB,throughput会比0.
8MB多不止两倍。当然区别也不大,但K更大时merge就是必须的了。(100路merge还是用
heap实现)。
3. N 路merge的话每个数据需要被读写logK/logN次。N大约等于内存大小/100MB,然后
视具数值调整。
4. 一个罗嗦的情况是各个数组不是random的。比如说一个数组整个都比另一个数组要
大。heap可以部分解决这种情况,但是不知道是不是最优的。大家再讨论一下。

的。

【在 x*****g 的大作中提到】
: 多个有序数组合并成一个有序数组。各数组长度不同。所有数组的所有元素都是唯一的。
: 就是说,任何数组中的任何元素与任何其他数组中的任何元素都不会相同。
: 另外,如果每个元素还带有一个属性,要随着元素移动,怎么办?建个结构?
: 有没有更好的办法?
: 谢谢!

1 (共1页)
进入Programming版参与讨论
相关主题
[合集] 很无聊的做了两道code jam哪位大侠给说说 何时用 merge sort, 何时用 quick sort, 何时
一道MS面试题 (转载)一个查找算法题
C里面的延时函数请教一个组合的算法
问一个随机排列的问题.问高手一个PERL的简单程序
N个数字里面找出最大的5个数字的复杂度是什么?O(N)?关于那个经典的missing number的题 (转载)
请问heap sort 数组时数组用preorder顺序存储怎么实现?从王垠的代码看似乎其没在正规公司呆过
如何将若干已升序排序好的数组合并在一起,并仍然是升序?linux 下从c++动态内存操作问题,heap size不够还是别的?
[合集] 一个已经排序好的数组,就是一个堆heap吗?Java数组怎么样能参数传递 (转载)
相关话题的讨论汇总
话题: 数组话题: heap话题: merge话题: pair话题: 合并