《排序算法》——归并排序,插入排序(Java)

简介: 一:归并排序 算法步骤: 1、申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 2、设定两个指针,最初位置分别为两个已经排好序列的起始位置 3、比较两个指针所指向的元素,选择相对小的元素到合并空间,并移动指针到下一位置 4、重复步骤3直到某一指针达到序列结尾 5、将另一序列下剩下的所有元素直接复制合并到序列结尾 归并排序用到了分治策略。

一:归并排序

算法步骤:

1、申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

2、设定两个指针,最初位置分别为两个已经排好序列的起始位置

3、比较两个指针所指向的元素,选择相对小的元素到合并空间,并移动指针到下一位置

4、重复步骤3直到某一指针达到序列结尾

5、将另一序列下剩下的所有元素直接复制合并到序列结尾

归并排序用到了分治策略。

用分治策略解决问题分为三步:分解、解决、合并。也即:将原来的问题划分为n个规模较小而结构与原问题相似的子问题,递归解决这些小问题,然后再合并其结果,得到原来问题的解。 此处n=2。

代码如下(有待优化):

import java.util.*;
public class main {
	//排序,开辟两个数组用于存放合并的数组
	public static void MERGE(int a[],int low,int mid,int last)
	{
	   int len_L = mid-low,len_R=last - mid+1;
	   int L[] = new int[len_L+1];
	   int R[] = new int[len_R+1];
	   for(int i =0;i<len_L;i++)
		   L[i] = a[low+i];
	   L[len_L] = Integer.MAX_VALUE;  //将其最后一个值设置成最大,是为了保证任何一个数组元素比较完之后另外一个数组的所有元素都能全部合并进去
	   for(int j =0;j<len_R;j++)
		   R[j]=a[mid+j];
	   R[len_R] = Integer.MAX_VALUE;
	   int i=0,j=0;
	   //比较将小的元素放在合并后的数组中,剩下的直接合并放进去
	   for(int k =low;k<last+1;k++)
		   if(L[i]<R[j]){
			   a[k]=L[i];
			   i++;
		   }
		   else{
			   a[k]=R[j];
			   j++;
		   }	   
	}

	
	public static void sort(int a[],int low,int last)
	{
		int mid = (low +last)/2;
		if(low <last){
			//拆分成无数个小问题
			sort(a,low,mid);
			sort(a,mid+1,last);
			//对小问题进行处理和解决
			MERGE(a,low,mid+1,last);
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
//		为了方便,直接给定数组了
//		int a[] = new int[10];
//      Scanner in = new Scanner(System.in); 
//		for(int i =0;i<10;i++)
//		{
//			a[i] = in.nextInt();
//		}
		int a[] = {3,2,4,7,5,6,9,1,8,0};
		sort(a,0,9);
		System.out.println(Arrays.toString(a));  
	}

}

归并排序举例

题目描述:有N个整数,A[1],A[2],A[3],....,A[N]。需要找打这样的(i,j)的数对的数量,满足 1 <= i < j <=N, A[i] > A[j]。数据范围:1<= N <= 65537

解决代码:

package sort;

import java.util.Arrays;
/*
 * 问题描述
 * 有N个整数,A[1],A[2],A[3],....,A[N]。需要找打这样的(i,j)的数对的数量
 * 满足 1 <= i < j <=N, A[i] > A[j]。数据范围:1<= N <= 65537,0 <=A[i] <=10^9
 */
public class guibingTest {

	static int[] arr = {
		3,4,1,5,2,6              //示例数组
	};
	static int num = 0; //记录满足条件的对数
	
	public static void main(String[] args) {
		MergeSort(arr, 0, 5);
		System.out.println("满足条件的逆序数 共:   " + num + "对");

	}
	
	//归并排序寻找满足条件的对数
		private static void MergeSort(int[] arr, int low, int high) {
			// TODO Auto-generated method stub
			int mid = (low + high) /2;
			if(low<high){
				//拆分进行排序
				MergeSort(arr, low,mid);
				MergeSort(arr, mid+1, high);
				Merge(arr,low,mid+1,high);        //合并排序后的数据
			}
		}

		//合并函数
		private static void Merge(int[] arr, int low, int mid, int high) {
			// TODO Auto-generated method stub
			int len_L = mid-low; // 左数组的长度
			int len_R = high-mid+1; //右数组的长度
			int[] L = new int[len_L];     //定义左数组
			int[] R = new int[len_R ]; //定义右数组
			
			//给左数组赋值
			for(int i =0 ; i< len_L;i ++)
				L[i] = arr[low+i];
			
			//给右数组赋值
			for(int j =0 ;j< len_R; j++)
				R[j] = arr[mid + j];
			
			//比较L 和 R 数组,若满足条件 计数器+1
			for(int i =0 ; i < len_L; i ++)
				for(int j=0; j <len_R; j ++)
					if(L[i] <= R[j])
					{
						System.out.println(L[i] + "\t" + R[j]);
						num++;
					}
		}
		
}



二:插入排序

算法思路:

假定n是数组的长度,

首先假设第一个元素被放置在正确的位置上,这样仅需从1-n-1范围内对剩余元素进行排序。对于每次遍历,从0-i-1范围内的元素已经被排好序,

每次遍历的任务是:通过扫描前面已排序的子列表,将位置i处的元素定位到从0到i的子列表之内的正确的位置上。

将arr[i]复制为一个名为target的临时元素。

向下扫描列表,比较这个目标值target与arr[i-1]、arr[i-2]的大小,依次类推。

这个比较过程在小于或等于目标值的第一个元素(arr[j])处停止,或者在列表开始处停止(j=0)。

在arr[i]小于前面任何已排序元素时,后一个条件(j=0)为真,

因此,这个元素会占用新排序子列表的第一个位置。

在扫描期间,大于目标值target的每个元素都会向右滑动一个位置(arr[j]=arr[j-1])。

一旦确定了正确位置j,

目标值target(即原始的arr[i])就会被复制到这个位置。

与选择排序不同的是,插入排序将数据向右滑动,并且不会执行交换。


程序实现:

package sort;

import java.util.Scanner;
/*
 * 插入排序
 * 时间复杂度: theta n^2
 */
public class insertSort {

	public static void main(String[] args) {
//		从键盘输入数组输入数组
//		Scanner scan = new Scanner(System.in);
//		int[] arr = new int[4];
//		for(int i =0;i<4;i++){
//			arr[i] = scan.nextInt();
//		}
		int[] arr ={3,1,5,2};
		//插入排序
		for(int i = 1; i<arr.length;i++){
			int key = arr[i];
			int j =i;
			while(j>0 && arr[j-1] > key){
				arr[j] = arr[j-1];
				j =  j-1;
			}
			arr[j] = key;
		}
		//输出数组
		System.out.println("排序后的数组为:");
		for(int i=0;i<arr.length;i++)
			System.out.print(arr[i] + "\t");
	}

}

相关文章
|
2月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
90 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
4月前
|
搜索推荐 算法 Java
手写快排:教你用Java写出高效排序算法!
快速排序(QuickSort)是经典的排序算法之一,基于分治思想,平均时间复杂度为O(n log n),广泛应用于各种场合。在这篇文章中,我们将手写一个Java版本的快速排序,从基础实现到优化策略,并逐步解析代码背后的逻辑。
172 1
|
2月前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
27 1
|
2月前
|
算法 搜索推荐
数据结构与算法学习十一:冒泡排序、选择排序、插入排序
本文介绍了冒泡排序、选择排序和插入排序三种基础排序算法的原理、实现代码和测试结果。
22 0
数据结构与算法学习十一:冒泡排序、选择排序、插入排序
|
2月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
85 2
|
2月前
|
存储 搜索推荐 算法
【排序算法(二)】——冒泡排序、快速排序和归并排序—>深层解析
【排序算法(二)】——冒泡排序、快速排序和归并排序—>深层解析
|
2月前
|
搜索推荐 算法
【排序算法(一)】——插入排序,选择排序 —> 深层解析
【排序算法(一)】——插入排序,选择排序 —> 深层解析
|
2月前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
76 0
|
2月前
|
搜索推荐 Java Go
深入了解归并排序算法
深入了解归并排序算法
26 0
|
4月前
|
算法 搜索推荐 Java
算法实战:手写归并排序,让复杂排序变简单!
归并排序是一种基于“分治法”的经典算法,通过递归分割和合并数组,实现O(n log n)的高效排序。本文将通过Java手写代码,详细讲解归并排序的原理及实现,帮助你快速掌握这一实用算法。
45 0