[英]Arrays and mergeSort in c++?
void Merge(int *array, int lo, int mid, int hi) {
int tArray[20];
int loBeg = lo;
int count = lo;
int hiBeg = mid + 1;
while (loBeg <= mid && hiBeg <= hi) {
if (array[loBeg] < array[hiBeg]) {
tArray[count] = array[loBeg];
loBeg++;
count++;
} else {
tArray[count] = array[hiBeg];
hiBeg++;
count++;
}
}
while (loBeg <= mid) {
tArray[count++] = array[loBeg++];
}
while (hiBeg <= hi) {
tArray[count++] = array[hiBeg++];
}
for (int i = 0; i < count; i++) {
array[i] = tArray[i];
}
}
void mergeSort(int *array, int lo, int hi) {
if (lo < hi) {
int mid = (lo + hi) / 2;
mergeSort(array, lo, mid);
mergeSort(array, mid + 1, hi);
Merge(array, lo, mid, hi);
}
}
int main(int argc, const char * argv[]) {
int array[] = {90, 99, 63, 82, 93, 76, 81, 76};
//int temp[8];
mergeSort(array, 0, 7);
for (int i = 0; i < 8; i++) {
std::cout << array[i] << std::endl;
}
return 0;
}
我的问题是关于此合并排序代码期间数组的性质。 该代码仅在设置为tArray[20];
将初始值设置为20。为什么不能将初始值设置为hi + 1
(在这种情况下为8
(与数组相同)? 但是,如果我取消注释temp[8]
数组,并通过mergeSort
和Merge
传递它,并在Merge
tArray
其用作tArray
(初始大小为8
),那么它将起作用。
我认为我的不了解也是我原始的merge()
)函数(如下所示)也不起作用的原因:
//this was my original merge code which does not work.
void merge(int *array, int lo, int mid, int hi) {
int tempArray[hi + 1];
int loBeg = lo;
int hiBeg = mid + 1;
for (int i = 0; i <= hi; i++) {
if (hiBeg > hi || (array[loBeg] < array[hiBeg] && loBeg <= mid)) {
tempArray[i] = array[loBeg++];
} else {
tempArray[i] = array[hiBeg++];
}
}
for (int i = 0; i <= hi; i++) {
array[i] = tempArray[i];
}
}
因此,基本上我想知道为什么在第一个Merge()
函数中,必须将tArray
初始大小设置为20
而不是与数组相同的大小,除非我从main
传递一个临时数组(初始化为相同的)大小为数组),然后,为什么我原来的merge()
函数不起作用,但是我认为这与我对第一个Merge()函数的理解不足有关。
当您创建这样的数组时: int array[20];
您将其分配到程序的堆栈存储器中。 在程序启动之前分配该内存。
问题来了。 当你尝试做int array[hi + 1];
您要求它分配程序启动之前未知的内存量,这会导致错误。
在这种情况下,您需要做的是使用动态内存。 运行时将分配并释放此内存。 意思是你可以做int* array = new int[hi + 1];
并且不会导致错误。
整个合并功能为:
void merge(int *array, int lo, int mid, int hi) {
int* tempArray = new int[hi + 1];
int loBeg = lo;
int hiBeg = mid + 1;
for (int i = 0; i <= hi; i++) {
if (hiBeg > hi || (array[loBeg] < array[hiBeg] && loBeg <= mid)) {
tempArray[i] = array[loBeg++];
} else {
tempArray[i] = array[hiBeg++];
}
}
for (int i = 0; i <= hi; i++) {
array[i] = tempArray[i];
}
delete[] tempArray;
}
我不建议您自己管理动态内存。 您应该为此使用STL: vector<int> tempArray(hi + 1);
而不是int* tempArray = new int[hi + 1];
。 这样,您不必具有delete[] tempArray;
在末尾。
合并排序被认为可用于列表,因为当您合并2个列表时,您可以将每个元素自由地附加到所需的元素上。
例:
Merge(List{3,4},List{5,6});
导致以下操作
List Merge(List a, List b){ //2 instructions even when Lists are long 1000000 elements
List newlist;
newlist.head = a.head;
newlist.tail = b.tail;
a.tail.next = b.head;
b.head.prev = a.tail;
return newList;
}
当您有数组时,实际上必须分配一个新大小的新数组:
int * Merge( int array* a, int array* b, unsigned int sizea, unsigned int sizeb){
//int tArray[20]; // :/ wrong
int * newarray = new int[sizea+sizeb];
for(unsigned int i=0; i<sizea; i++)
newarray[i]=a[i];
for(unsigned int i=0; i<sizeb; i++)
newarray[i+sizea]=a[i];
delete []a;
delete []b;
return newarray;
}
附带地,这使算法更加昂贵。 即使在您已经预分配了足够大的数组的情况下,算法的成本也更高,因为您必须在每次合并时复制所有元素。
您的代码中有多个问题,其中有几个:
void Merge(int *array, int lo, int mid, int hi) {
// The size should be hi - lo + 1, not hi + 1
int tArray[hi + 1];
int loBeg = lo;
// count should start at 0, not lo
int count = lo;
int hiBeg = mid + 1;
while (loBeg <= mid && hiBeg <= hi) {
if (array[loBeg] < array[hiBeg]) {
tArray[count] = array[loBeg];
loBeg++;
count++;
} else {
tArray[count] = array[hiBeg];
hiBeg++;
count++;
}
}
while (loBeg <= mid) {
tArray[count++] = array[loBeg++];
}
while (hiBeg <= hi) {
tArray[count++] = array[hiBeg++];
}
for (int i = 0; i < count; i++) {
// it should be array[lo + i], not array[i]
array[i] = tArray[i];
}
}
以下是3个错误的一些解释:
您不希望每次都使用hi + 1
大小的数组,当您沿着“合并树”浏览时,必须合并较小大小的数组,因此需要使用hi - lo + 1
。 实际上,在这种情况下,使用hi + 1
应该不是问题,但是您分配的内存超出了实际需要。
您不应该从lo
开始,而应该从0
,否则您的tArray[count]
将tArray[count]
。 在您的情况下,从lo
开始工作是因为您要分配一个非常大的数组(大小为20
或hi + 1
),但不适用于大小为hi - lo + 1
的数组,因此请务必小心。
也许是最大的错误-您一直在替换原始数组的第一个count
单元...不! 您要替换lo
和hi
之间的单元格,而不是0
和count
之间的单元格。
您需要记住,在调用Merge (array, lo, mid, hi)
,您想将array[lo:mid]
和array[mid+1:hi]
合并为array[lo:hi]
。
以下是一些详细说明:
让我们从下面的数组[90, 99, 63, 82, 93, 76, 81, 76]
mergeSort
[90, 99, 63, 82, 93, 76, 81, 76]
,在对mergeSort
每次调用中,您将数组分为两个相等的部分:
第一次获得[90, 99, 63, 82]
( lo = 0
, hi = 3
)和[93, 76, 81, 76]
( lo = 4
, hi = 7
),并且不断除法直到得到8
个大小为1
数组。 为了简单起见([90], 0, 0)
我将编写(array, lo, hi)
,例如([90], 0, 0)
。
您应该到达具有([90], 0, 0)
, ([99], 1, 1)
,依此类推...将这些2乘以2,所以(例如)将要合并([93], 4, 4)
和([76], 5, 5)
。 合并这两个数组时,您将得到如下所示的Merge
调用:
Merge (array, 4, 4, 5) // mid is (4 + 5) / 2 = 4
那么, Merge
功能会发生什么?
您应该已经注意到,由于要合并两个大小为1的数组( [93]
和[76]
),因此需要一个大小为2的临时数组。如果使用tArray[hi + 1]
,则分配一个大小为hi + 1 = 6
的数组hi + 1 = 6
,这比您实际需要的要大得多(在这里可能不会有很大的不同,但是请想象您是否有原始大小为10亿的数组!)。 因此,分配大小为hi - lo + 1 = 5 - 4 + 1 = 2
的数组就足够了。
您实际上是初始数组的4
到5
范围,因此您要处理该部分,而又不想删除已经排序的0
到1
部分! 但是,如果在循环中执行array[i] = tArray[i]
,会发生什么? 好吧, i
从0
开始并开始count
(在这种情况下应该为2
),所以您要替换array[0]
和array[1]
而不是array[4]
和array[5]
。 这可以通过执行array[lo + i]
而不是array[i]
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.