日撸代码300行:第49天(归并排序)

本文详细解析了Java实现归并排序的过程,包括分配空间、设置变量、循环控制及不同情况下的数据合并。通过例子展示了如何避免常见的编程错误,如数组声明错误和逻辑错误。文章还提供了完整的归并排序代码实现,并给出了测试用例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码来自闵老师”日撸 Java 三百行(41-50天)“,链接:https://blog.youkuaiyun.com/minfanphd/article/details/116975863

最近对于代码学习的执行力越来越差,每天断断续续学,结果一个归并排序用了这么久。今天对归并排序进行一下总结梳理。
归并排序的思想是将数据分成一个一个的数据,然后每次按照2个组,合并在一起排序,直到最后合并成一组数。共进行log n轮排序,每一轮共有length / (tempSize * 2)组,其中tempSize指的是该轮循环的步长。

	/**
	 * *******************************************************
	 * Merge sort. Results are stored in the member variable data.
	 * *******************************************************
	 */
	public void mergeSort() {
		// Step 1. Allocate space.
		int tempFirstStart, tempSecondStart, tempSecondEnd;
		int tempFirstIndex, tempSecondIndex;
		int tempRow; 
		int tempNextRow = 0;
		int tempActualRow;
		int tempGroups;
		int tempGroupNumber;
		int tempNumCopied;
		
		DataNode[][] tempMatrix = new DataNode[2][length];
		
		for (int i = 0; i < length; i++) {
			System.out.print(data[i]);
		}//of for i
		System.out.println();
		
		//copy data.
		for (int i = 0; i < length; i++) {
			tempMatrix[0][i] = data[i];
		}//of for i
		
		tempRow = -1;
		for (int tempSize = 1; tempSize < length; tempSize = tempSize * 2) {
			// Reuse the space of the two rows. 
			tempRow++;
			tempActualRow = tempRow % 2 ;
			tempNextRow = (tempRow + 1) % 2;
			
			tempGroups = length / (tempSize * 2);
			if (length % (tempSize * 2) != 0) {
				tempGroups++;
			}//of if
			
			for (tempGroupNumber = 0; tempGroupNumber < tempGroups; tempGroupNumber++) {
			tempFirstStart = 2 * tempGroupNumber * tempSize;
			tempSecondStart = 2 * tempGroupNumber * tempSize + tempSize;
			if (tempSecondStart > length - 1) {
				// Copy the first part. Because the following three while loops 
				//do not meet this condition, you need to copy the data of the first group.
				for (int i = tempFirstStart; i < length; i++) {
					tempMatrix[tempNextRow][i] = tempMatrix[tempActualRow][i]; 
				}//of for i
				continue;
			}//of if
			tempSecondEnd = 2 * tempGroupNumber * tempSize + 2 * tempSize - 1;
			//Because the following three while loops contain conditions 
			//that meet this condition, there is no need to copy data.
			if (tempSecondEnd > length - 1) {
				tempSecondEnd = length - 1;
			}//of if
			
			tempFirstIndex = tempFirstStart;
			tempSecondIndex = tempSecondStart;
			tempNumCopied = 0;
			
			System.out.println("tempFirstStart & tempSecondStart" + tempFirstStart + " " + tempSecondStart);
			
			while ((tempFirstIndex <= tempSecondStart - 1) && (tempSecondIndex <= tempSecondEnd)) {
				if (tempMatrix[tempActualRow][tempFirstIndex].key <= tempMatrix[tempActualRow][tempSecondIndex].key) {
					tempMatrix[tempNextRow][tempFirstStart + tempNumCopied] = tempMatrix[tempActualRow][tempFirstIndex];
					tempFirstIndex++;
				}else {
					tempMatrix[tempNextRow][tempFirstStart + tempNumCopied] = tempMatrix[tempActualRow][tempSecondIndex];
					tempSecondIndex++;
				} //of if
				tempNumCopied++;
				
				System.out.println("tempNumCopied of while 1: " + tempNumCopied);
				
			}//of while
			
			while (tempFirstIndex <= tempSecondStart - 1) {
				tempMatrix[tempNextRow][tempFirstStart + tempNumCopied] = tempMatrix[tempActualRow][tempFirstIndex];
				tempFirstIndex++;
				tempNumCopied++;
			}//of while
			System.out.println("tempNumCopied of while 2: " + tempNumCopied);
			System.out.println("tempSecondEnd of while 2: " + tempSecondEnd);
			while (tempSecondIndex <= tempSecondEnd) {
				tempMatrix[tempNextRow][tempFirstStart + tempNumCopied] = tempMatrix[tempActualRow][tempSecondIndex];
				tempSecondIndex++;
				tempNumCopied++;
			}//of while
			System.out.println("tempNumCopied of while 3: " + tempNumCopied);
			System.out.println("tempSecondEnd of while 3: " + tempSecondEnd);
			}//of for tempGroupNumber
		}//of for tempSize
		data = tempMatrix[tempNextRow];
	}//of mergeSort
	
	/**
	 * ********************************************************
	 * Test the method.
	 * ********************************************************
	 */
	public static void mergeSortTest() {
		int[] tempUnsortedKeys = { 5, 3, 6, 10, 7, 1, 9 };
		String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while" };
		DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);
		
		System.out.println(tempDataArray);
		tempDataArray.mergeSort();
		System.out.println("Result\r\n" + tempDataArray);
	}//of mergeSortTest

归并排序的思路梳理如下:
1、分配空间,需声明各种变量。变量有归并时第一组的开始、第二组的开始和结尾;归并时第一组的序列、第二组的序列;数据在每一轮的组数、组序列;申请的两个排序空间循环使用,就存在当前列和下一列。还需要两个变量做“标尺”变量,一个是tempRow,用于自生长记录然后对2取余循环使用分配的两组空间;第二个是用于记录当前归并组内排序了几个数(这里记为tempNumCopied),然后下一个排序的数就放在tempNextRow的firstIndex + tempNumCopied 的位置。
2、for循环,用于控制循环的轮数,步长(tempSize)递增方式为每次乘以2。该for循环里有一些准备工作,比如两组空间的循环使用,还有组数tempGroups的计算,如果不为整数采取上取整。
3、for循环内部嵌套的第二个for循环,作为主要是按照组数循环,即每一轮需要归并多少次。该for循环也有一些准备工作,需要初始化第一组的开始以及第二组的开始和结束;初始化第一组、第二组的序列,初始化每一轮当前组排序个数tempNumCopied。这里需要注意tempSecondEnd如果有大于length-1,即超过数据总长度的情况,需修改tempSecondEnd为数据总长度。
4、正式进行归并排序,分为三种情况进行while循环。
第一个while循环是每一组的第一个小组的序列小于第二个小组的开头,且第二个小组的序列小于第二个小组的结束。也就是说当前的while循环处理的是两个小组内的数据都没有排序结束的情况。
第二个while循环是每一组第一个小组的序列小于第二个小组的开始,也就是第二个小组已排序完成,但是第一个小组没有排序完成的情况。此时将第一小组的剩余数据全部复制到tempNextRow的对应位置即可。
第三个while循环是第一个小组已经排序完成,但是第二个小组还有剩余数据。此时将第二个小组的剩余数据全部复制到tempNextRow的对应位置即可。
5、最终循环结束需要将tempMatrix[tempNextRow](排序好)的数据赋值于data保存。

自己写代码的过程中共出现两个错误:
1、DataNode[][] tempMatrix = new DataNode[2][length];写成了DataNode[][] tempMatrix = new DataNode[2][];出现该错误是数组声明没搞清楚,属于语法错误,数组声明应该是行可以空,列不能空。
2、tempGroups = length / (tempSize * 2);写成了tempGroups = length %(tempSize * 2);出现该错误是逻辑错误,取余第一轮的时候就只有两组。而其实算法的第一轮应该是有length/2组,第二轮应该有length/(2*2)组,依次类推。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值