zuochengyun_算法基础课_01笔记(归并排序)

一、 排序方式

冒泡排序、选择排序、插入排序、归并排序;

1、冒泡排序

原理:相邻元素相比较,每遍历一次,就在数组的末尾确定一个max值。
“向后沉,相邻排”

2、选择排序

原理:每遍历一次,确定一个min值存放在数组首段。
“借用min存放,再相交换”

3、插入排序

原理:假设前i个已经排列好顺序,将第i+1个插入进已排好的序列中。

冒泡排序、选择排序、插入排序代码

package basis_01_myExamination;

public class sort {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] arr=new int[]{0,2,1,5,3,8};
		//TEST1:冒泡排序测试
		//arr=bubbleSort(arr);
		//printArray(arr);
		
		//TEST2:选择排序测试
		//arr=selectSort(arr);
		//printArray(arr);
		
		//TEST3:插入排序测试
		arr=insertSort(arr);
		printArray(arr);
		
		

	}
	//冒泡排序:向后沉,相邻比较;
	public static int[] bubbleSort(int[] arr){
		for(int i=arr.length-1 ; i>0 ; i--){
			for(int j=0 ; j<i ; j++){
				if(arr[j]>arr[j+1]){
					change(arr,j,j+1);
				}		
			}	
		}
		return arr;
	}
	
	//选择排序
	public static int[] selectSort(int[] arr){
		int min;
		for(int i=0;i<arr.length;i++){
			min=i;
			for(int j=i+1;j<arr.length;j++){
				if(arr[min]>arr[j]){
					min=j;
				}
			}
			change(arr,i,min);
		}
		return arr;
	}
	
	//插入排序
	public static int[] insertSort(int[] arr){
		for(int i=1;i<arr.length;i++){
			/*for(int j=i-1;j>=0;j--){
				if(arr[j]>arr[j+1]){
					change(arr,j,j+1);
				}
			}*/
			//上面的for+if语句可以将if语句合并到for语句中;
			for(int j=i-1;j>=0 && arr[j]>=arr[j+1];j--){
				change(arr,j,j+1);
			}	
		}
		return arr;
	}
	
	
	
	
	//交换两个元素
	public static void change(int[] arr, int p1, int p2){
		int temp=arr[p1];
		arr[p1]=arr[p2];
		arr[p2]=temp;
	}
	
	//打印一个数组
	public static void printArray(int[] arr){
		for(int i=0;i<arr.length;i++){
			System.out.println(arr[i]);
		}
	}
	
}

二、归并排序

一、原理

递归+外排的思路;
“将左右两边分别排好,再合并排好”

二、常见应用

1、求数组小和
merge函数设计;
merge原理:对于两个有序的数组,如果p1所指的数,比p2小,则p1比p2及其之后的元素都小,计算:p1*(p2及其之后元素的个数)
2、求数组逆序对
merge函数的设计:
merge原理:对于两个有序的数组,如果p1所指的元素大于p2,则p1及其之后的每一个元素都大于p2,都与p2构成一个逆序对。
3、数组小和、逆序对代码

	//Q3:求解小和问题
	//小和问题描述:在一个数组,每一个数左边的数,比当前数小的累计和,称为改数组的小和;
	//思路:归并排序
	//     左边求最小和:递归,调用自己smallSum
	//     右边求最小和:递归,调用自己smallSum
	//     合并求最小和:merge函数;
	public static int smallSum(int[] arr,int L,int R){
		
		if(L==R)
			return 0;
		
		int mid=L+((R-L)>>2);
		int leftSum=smallSum(arr,L,mid);
		int rightSum=smallSum(arr,mid+1,R);
		int mergesum=mergeSum(arr,L,mid,R);
		//左边的最小和+右边的最小和+合并后的最小和
		return leftSum+rightSum+mergesum;
	}	
	public static int mergeSum(int[] arr, int L,int mid, int R){
		int p1=L;
		int p2=mid+1;
		int[] helpArr=new int[(R-L+1)];
		int i=0;
		int sum=0;
		while(p1<=mid&&p2<=R){
			//注意,在helpArr数组之前,不能改变p1和p2的值
			sum =+ arr[p1]< arr[p2]? arr[p1]*(R-p2+1):0;
			helpArr[i++]=arr[p1]< arr[p2]?arr[p1++]:arr[p2++];
		}
		while(p1<=mid)
			helpArr[i++]=arr[p1++];
		while(p2<=R)
			helpArr[i++]=arr[p2++];
		
		for(int j=0;j<helpArr.length;j++)
			//arr[L++]=helpArr[j];错误,不能改变L的值。
			arr[L+j]=helpArr[j]; 
		
		return sum;	
	}
	
	
	//Q4:逆序对问题
	//在一个数组中,如果左边的数比右边的数大,则两个数构成一个逆序对,求一个数组的所有逆序对;
	//思路:
	
	public static void reverseOrder(int[] arr, int L, int R){
		if(L==R)
			return;
		 int mid=L+((R-L)>>2);
		 reverseOrder(arr,L,mid);
		 reverseOrder(arr,mid+1,R);
		 mergeOrder(arr,L,mid,R);
	}
	public static void mergeOrder(int[] arr, int L,int mid, int R){
		int p1=L;
		int p2=mid+1;
		int[] helpArr=new int[(R-L+1)];
		int i=0;
		while(p1<=mid&&p2<=R){
			//注意,在helpArr数组之前,不能改变p1和p2的值
			//当p1所指的数,比p2所指的数大时,则说明,p1及其之后的全部数,都比p2大,即p1即其之后的全部数,都和p2构成逆序;
			if(arr[p1]>arr[p2]){
				int m=p1;
				while(m<=mid){
					System.out.println(arr[m++]+" "+arr[p2]);
				}
			}
			
			helpArr[i++]=arr[p1] < arr[p2] ? arr[p1++] : arr[p2++]; //保证了两个小数组,始终有序,且为升序排序
		}
		while(p1<=mid){
			helpArr[i++]=arr[p1++];
		}
		while(p2<=R){
			helpArr[i++]=arr[p2++];
		}
		for(int j=0; j<helpArr.length; j++){
			arr[L+j]=helpArr[j];
		}
	}

三、对数器

一、对数器的作用
(1)在没有OG时,利用对数器测试算法的正确性;
(2)验证贪心算法的正确性;
(3)在测试小OG时算法通过,但是测试大OG时算法错误,可以利用对数器迅速找到错误原因。
(4)当无法得到一个完全正确的对比算法时,利用对数器将每次错误的OG样本和OG结果打印出来,人为干预,对OG样本进行干预,判断错误的对象和原因,人为进行调整。
二、对数器的原理
Step1:设计一个随机样本产生器;
Step2:设计一个时间复杂度和空间复杂度没有那么好的绝对正确的对比算法;
Step3:利用随机样本产生器,多次产生OG,对两个算法进行测试,并比较二者的结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
归并排序(Merge Sort)是一种稳定的、基于比较的排序算法,最坏时间复杂度为 O(nlogn)。其基本思想是将待排序序列分成若干个子序列,每个子序列都是有序的,然后将子序列合并成整体有序的序列。 归并排序的实现方法有两种:自顶向下和自底向上。 自顶向下的归并排序算法实现: 1. 将待排序序列分成两个子序列,分别对这两个子序列进行递归排序。 2. 将两个已经排好序的子序列合并为一个有序序列。 自底向上的归并排序算法实现: 1. 将待排序序列每个元素看成一个独立的有序序列,进行两两合并。 2. 得到 n/2 个长度为 2 的有序序列,再两两合并。 3. 重复步骤 2,直到得到一个长度为 n 的有序序列。 下面是自顶向下的归并排序算法的实现代码(使用了递归): ``` void MergeSort(int arr[], int left, int right) { if (left >= right) return; int mid = left + (right - left) / 2; MergeSort(arr, left, mid); MergeSort(arr, mid + 1, right); int* temp = new int[right - left + 1]; int i = left, j = mid + 1, k = 0; while (i <= mid && j <= right) { if (arr[i] <= arr[j]) temp[k++] = arr[i++]; else temp[k++] = arr[j++]; } while (i <= mid) temp[k++] = arr[i++]; while (j <= right) temp[k++] = arr[j++]; for (int p = 0; p < k; p++) arr[left + p] = temp[p]; delete[] temp; } ``` 下面是自底向上的归并排序算法的实现代码(使用了迭代): ``` void MergeSort(int arr[], int n) { int* temp = new int[n]; for (int len = 1; len < n; len *= 2) { for (int left = 0; left < n - len; left += len * 2) { int mid = left + len - 1; int right = min(left + len * 2 - 1, n - 1); int i = left, j = mid + 1, k = 0; while (i <= mid && j <= right) { if (arr[i] <= arr[j]) temp[k++] = arr[i++]; else temp[k++] = arr[j++]; } while (i <= mid) temp[k++] = arr[i++]; while (j <= right) temp[k++] = arr[j++]; for (int p = 0; p < k; p++) arr[left + p] = temp[p]; } } delete[] temp; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值