持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第27天,点击查看活动详情
归并排序
基本思路
归并是将两个或两个以上的有序表组合成一个新的有序表,归并排序是分治思想的应用(分而治之)。
如下是手动模拟二路归并排序,如下有7个数,
进行两两排序,得⌈7/2⌉=4(向上取整)有4个长度为2或1的分组,对每个分组进行排序,再进行⌈7/4⌉=2 有2个长度为4或3的分组,进行分组排序后,⌈7/7⌉=1 长度为7的一个分组,对这个分组进行排序。如下图所示
代码实现
根据今天的代码,我觉得还是读起来挺有难度的,首先是他的变量太多,其次在为每一次排序时,分多少组,分组长度不一致怎么解决以及分好组后如何进行排序等一些比较细节的东西,都觉得还挺难理解。所以在段代码是需要结合图形来看才能更好的吸收内容,
public void mergeSort() {
int tempRow;
int tempGroups;
int tempActualRow; // Only 0 or 1
int tempNextRow = 0;
int tempGroupNumber;
int tempFirstStart, tempSecondStart, tempSecondEnd;
int tempFirstIndex, tempSecondIndex;
int tempNumCopied;
for (int i = 0; i < length; i++) {
System.out.print(data[i]);
}
System.out.println();
DataNode[][] tempMatrix = new DataNode[2][length];
for (int i = 0; i < length; i++) {
tempMatrix[0][i] = data[i];
}
// Step 3. Merge. log n rounds
tempRow = -1;
//进行几趟归并排序
for (int tempSize = 1; tempSize <= length; tempSize *= 2) {
// Reuse the space of the two rows.
tempRow++;
System.out.println("Current row = " + tempRow);
tempActualRow = tempRow % 2;
tempNextRow = (tempRow + 1) % 2;
// 在每趟排序中需要分为几组 乘以2是因为是2路归并
tempGroups = length / (tempSize * 2);
if (length % (tempSize * 2) != 0) {
tempGroups++;
}
System.out.println("tempSize = " + tempSize + ", numGroups = " + tempGroups);
//对两两分组进行排序
for (tempGroupNumber = 0; tempGroupNumber < tempGroups; tempGroupNumber++) {
//两组的起始位置
tempFirstStart = tempGroupNumber * tempSize * 2;
tempSecondStart = tempGroupNumber * tempSize * 2 + tempSize;
//所第二个分组是超出长度
if (tempSecondStart > length - 1) {
// 直接赋值数据 因为两两比较的数组本身是有序的
for (int i = tempFirstStart; i < length; i++) {
tempMatrix[tempNextRow][i] = tempMatrix[tempActualRow][i];
}
continue;
}
//判断第而个分组与第一个是否等长 不等长则需要调整结尾是长度
tempSecondEnd = tempGroupNumber * tempSize * 2 + tempSize * 2 - 1;
if (tempSecondEnd > length - 1) {
tempSecondEnd = length - 1;
} // Of if
System.out.println("Trying to merge [" + tempFirstStart + ", " + (tempSecondStart - 1)
+ "] with [" + tempSecondStart + ", " + tempSecondEnd + "]");
tempFirstIndex = tempFirstStart;
tempSecondIndex = tempSecondStart;
tempNumCopied = 0;
while ((tempFirstIndex <= tempSecondStart - 1)
&& (tempSecondIndex <= tempSecondEnd)) {
if (tempMatrix[tempActualRow][tempFirstIndex].key <= tempMatrix[tempActualRow][tempSecondIndex].key) {
tempMatrix[tempNextRow][tempFirstStart + tempNumCopied] = tempMatrix[tempActualRow][tempFirstIndex];
tempFirstIndex++;
System.out.println("copying " + tempMatrix[tempActualRow][tempFirstIndex]);
} else {
tempMatrix[tempNextRow][tempFirstStart + tempNumCopied] = tempMatrix[tempActualRow][tempSecondIndex];
System.out.println("copying " + tempMatrix[tempActualRow][tempSecondIndex]);
tempSecondIndex++;
} // Of if
tempNumCopied++;
} // Of while
while (tempFirstIndex <= tempSecondStart - 1) {
tempMatrix[tempNextRow][tempFirstStart + tempNumCopied] = tempMatrix[tempActualRow][tempFirstIndex];
tempFirstIndex++;
tempNumCopied++;
} // Of while
while (tempSecondIndex <= tempSecondEnd) {
tempMatrix[tempNextRow][tempFirstStart + tempNumCopied] = tempMatrix[tempActualRow][tempSecondIndex];
tempSecondIndex++;
tempNumCopied++;
} // Of while
} // Of for groupNumber
System.out.println("Round " + tempRow);
for (int i = 0; i < length; i++) {
System.out.print(tempMatrix[tempNextRow][i] + " ");
} // Of for j
System.out.println();
} // Of for tempStepSize
data = tempMatrix[tempNextRow];
}
总结:
今天学习归并排序,在代码实现上我理解了许久,这个有些花时间,我参考了一些其他的归并排序方法,采用的2路递归的方式,因为递归对我们来说读起来很容易,想把递归转为非递归难度就会加大,就像今天采用的非递归的方法,里面需要考虑到很多细节。