这里有第一个问题,是的,这是一个家庭作业问题。我们的任务是在数组上执行合并排序(我很熟悉),但在某种程度上我不确定如何做。通常我会有一个单独的合并和合并排序功能,并使用这两个。然而,听起来他想用一种方法做所有事情?我只是希望也许有人可以帮我清理一下,或者说出我能更好理解的条款。
来自作业:
您需要实现merge-sort的非递归版本 算法。安排两个嵌套循环来完成此任务。外面的 loop应该提供合并段的大小。内循环 应该注意选择细分的位置。内循环 应该从左边缘开始并将您的线段向右移动。 安排适当的变量值left,middle,right,这样 只需通过迭代调用即可完成排序 合并(A,左,中,右)。
我讨厌这么模糊,但我真的不明白他说的是什么。首先,“外环应该提供段的大小”是什么意思?循环如何提供任何东西?下一句话怎么样?他对段的意思是什么?数据?
我不是要求代码,但任何伪代码都会非常有用。
如果有人试图破译他的意思,我会很感激。我已经通过电子邮件向他发了电子邮件,但已经过了几个小时,我还没有收到回复。
谢谢!
答案 0 :(得分:44)
这并不困难。考虑递归合并:
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
/ \ split
+-+-+-+-+ +-+-+-+-+
| | | | | | | | | |
+-+-+-+-+ +-+-+-+-+
/ \ / \ split
+-+-+ +-+-+ +-+-+ +-+-+
| | | | | | | | | | | |
+-+-+ +-+-+ +-+-+ +-+-+
/ \ / \ / \ / \ split
+-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
| | | | | | | | | | | | | | | |
+-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
\ / \ / \ / \ / merge
+-+-+ +-+-+ +-+-+ +-+-+
| | | | | | | | | | | |
+-+-+ +-+-+ +-+-+ +-+-+
\ / \ / merge
+-+-+-+-+ +-+-+-+-+
| | | | | | | | | |
+-+-+-+-+ +-+-+-+-+
\ / merge
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
如果您注意到,当您分手时,您并没有真正做任何事情。您只需告诉递归函数对数组进行部分排序。对数组进行排序包括首先对两半进行排序然后合并它。所以基本上,你拥有的是:
+-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
| | | | | | | | | | | | | | | |
+-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
\ / \ / \ / \ / merge
+-+-+ +-+-+ +-+-+ +-+-+
| | | | | | | | | | | |
+-+-+ +-+-+ +-+-+ +-+-+
\ / \ / merge
+-+-+-+-+ +-+-+-+-+
| | | | | | | | | |
+-+-+-+-+ +-+-+-+-+
\ / merge
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
现在从这里开始就应该是显而易见的。你首先合并数组2的元素2,然后4乘4,然后8乘8等。那就是外for
给你2,4,8,16,32 ......(这是什么它调用段的大小,因为循环的i
包含该数字)并且内部for
(比如迭代器j
)遍历数组, i
i
将array[j...j+i/2-1]
与array[j+i/2..j+i-1]
合并。{/ p>
我不会写代码,因为这是作业。
编辑:内部for
如何运作的图片
想象一下,如果i
是4,那么你就处于这个阶段:
+-+-+ +-+-+ +-+-+ +-+-+
| | | | | | | | | | | |
+-+-+ +-+-+ +-+-+ +-+-+
\ / \ / merge
+-+-+-+-+ +-+-+-+-+
| | | | | | | | | |
+-+-+-+-+ +-+-+-+-+
您将拥有一个for
,一次为您0
(0*i
)为j
,然后为4
(1*i
})j
。 (如果i
为2,则j
将为0,2,4,6)
现在,您需要将array[0..1]
与array[2..3]
合并(由array[j..j+i/2-1]
和array[j+i/2..j+i-1]
与j = 0
合并)然后{{1} array[4..5]
{由array[6..7]
和array[j...j+i/2-1]
制定,因为现在array[j+i/2..j+i-1]
)即:
j = 4
希望至少有一点清楚。
帮助:如果你真的不知道i = 4:
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | |
/ / / / \ \ \ \
(j = 0) (j = 4)
| | | | | | | |
j | | | j | | |
| | | j+i-1 | | | j+i-1
| | j+i/2 | | j+i/2
| j+i/2-1 | j+i/2-1
| | | | | | | |
| | | | | | | |
\ / \ / \ / \ /
v v v v
merge merge
是如何运作的,那就是一个提示:
for
就像写作
for (statement1; condition; statement2)
{
// processing
}
所以,如果你总是写
statement1;
while (condition)
{
// processing
statement2;
}
它意味着从0开始,而for (int i = 0; i < 10; ++i)
小于10,使用i
执行某些操作然后递增它。现在,如果您希望i
以不同方式进行更改,则只需更改i
,例如:
statement2
(尝试根据我写给你的等效for (int i = 1; i < 1024; i *= 2)
了解最终for
的工作原理。
答案 1 :(得分:2)
std::merge
的懒惰,迭代/自下而上的合并排序实现:template<class InIt, class OutIt>
OutIt mergesort(InIt begin, InIt const end, OutIt o /* auxiliary buffer */)
{
ptrdiff_t j;
for (j = 0; begin != end; ++begin, ++j)
{
for (ptrdiff_t n = 1; n <= j && j % (n * 2) == 0; n *= 2)
{
o = std::merge(o - n * 2, o - n, o - n, o, begin - n * 2);
o = std::swap_ranges(begin - n * 2, begin, o - n * 2);
}
*o = *begin;
++o;
}
--j;
for (ptrdiff_t m = 1, n = 1; n <= j; n *= 2)
{
if (j & n)
{
o = std::merge(o - (m + n), o - m, o - m, o, o - (m + n));
o = std::swap_ranges(begin - (m + n), begin, o - (m + n));
m += n;
}
}
return o;
}
std::inplace_merge
template<class InIt>
InIt inplace_mergesort(InIt begin, InIt const end)
{
ptrdiff_t j;
for (j = 0; begin != end; ++begin, ++j)
{
for (ptrdiff_t n = 1; n <= j && j % (n * 2) == 0; n *= 2)
{ std::inplace_merge(begin - n * 2, begin - n, begin); }
}
--j;
for (ptrdiff_t m = 1, n = 1; n <= j; n *= 2)
{
if (j & n)
{
std::inplace_merge(begin - (m + n), begin - m, begin);
m += n;
}
}
return begin;
}
答案 2 :(得分:0)
这是自下而上合并的C#版本(有关更多详细信息,请参阅我的博客@ http://dream-e-r.blogspot.com/2014/07/mergesort-arrays-and-lists.html)
void BottomUpMergesort(int[] a)
{
int[] temp = new int[a.Length];
for (int runWidth = 1; runWidth < a.Length; runWidth = 2 * runWidth)
{
for (int eachRunStart = 0; eachRunStart < a.Length;
eachRunStart = eachRunStart + 2 * runWidth)
{
int start = eachRunStart;
int mid = eachRunStart + (runWidth - 1);
if(mid >= a.Length)
{
mid = a.Length - 1;
}
int end = eachRunStart + ((2 * runWidth) - 1);
if(end >= a.Length)
{
end = a.Length - 1;
}
this.Merge(a, start, mid, end, temp);
}
for (int i = 0; i < a.Length; i++)
{
a[i] = temp[i];
}
}
合并定义为:
void Merge(int[] a, int start, int mid, int end, int[] temp)
{
int i = start, j = mid+1, k = start;
while((i<=mid) && (j<=end))
{
if(a[i] <= a[j])
{
temp[k] = a[i];
i++;
}
else
{
temp[k] = a[j];
j++;
}
k++;
}
while(i<=mid)
{
temp[k] = a[i];
i++;
k++;
}
while (j <= end)
{
temp[k] = a[j];
j++;
k++;
}
Assert.IsTrue(k == end+1);
Assert.IsTrue(i == mid+1);
Assert.IsTrue(j == end+1);
}
}
这里仅供参考:TopDownMergesort:
void TopDownMergesort(int[] a, int[] temp, int start, int end)
{
if(start==end)
{
//run size of '1'
return;
}
int mid = (start + end) / 2;
this.TopDownMergesort(a, temp, start, mid);
this.TopDownMergesort(a, temp, mid + 1, end);
this.Merge(a, start, mid, end, temp);
for(int i = start;i<=end;i++)
{
a[i] = temp[i];
}
}
<强>单元测试强>
[TestMethod]
public void BottomUpMergesortTests()
{
int[] a = { 13, 4, 1, 3, 8, 11, 9, 10 };
this.BottomUpMergesort(a);
int[] b = { 1, 3, 4, 8, 9, 10, 11, 13 };
Assert.IsTrue(a.Length == b.Length);
for (int i = 0; i < a.Length; i++)
{
Assert.IsTrue(a[i] == b[i]);
}
List<int> l = new List<int>();
for (int i = 10; i >= 1; i--)
{
l.Add(i);
}
var la = l.ToArray();
this.BottomUpMergesort(la);
for (int i = 1; i <= 10; i++)
{
Assert.IsTrue(la[i - 1] == i);
}
l.Clear();
for (int i = 16; i >= 1; i--)
{
l.Add(i);
}
la = l.ToArray();
this.BottomUpMergesort(la);
for (int i = 1; i <= l.Count; i++)
{
Assert.IsTrue(la[i - 1] == i);
}
}
答案 3 :(得分:0)
这是Java实现
public static <T extends Comparable<? super T>> void iterativeMergeSort(T[] seed) {
for (int i = 1; i <seed.length; i=i+i)
{
for (int j = 0; j < seed.length - i; j = j + i+i)
{
inPlaceMerge(seed, j, j + i-1, Math.min(j+i + i -1, seed.length -1));
}
}
}
public static <T extends Comparable<? super T>> void inPlaceMerge(T[] collection, int low, int mid, int high) {
int left = low;
int right = mid + 1;
if(collection[mid].equals(collection[right])) {
return ;//Skip the merge if required
}
while (left <= mid && right <= high) {
// Select from left: no change, just advance left
if (collection[left].compareTo(collection[right]) <= 0) {
left ++;
} else { // Select from right: rotate [left..right] and correct
T tmp = collection[right]; // Will move to [left]
rotateRight(collection, left, right - left);
collection[left] = tmp;
// EVERYTHING has moved up by one
left ++; right ++; mid ++;
}
}
}
这是单元测试 private Integer [] seed;
@Before
public void doBeforeEachTestCase() {
this.seed = new Integer[]{4,2,3,1,5,8,7,6};
}
@Test
public void iterativeMergeSortFirstTest() {
ArrayUtils.<Integer>iterativeMergeSort(seed);
Integer[] result = new Integer[]{1,2,3,4,5,6,7,8};
assertThat(seed, equalTo(result));
}