一:归并排序
算法步骤:
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"); } }