《算法》逆序数组,选择排序和插入排序谁更快

2.1.6  在所有的主键都相同时,选择排序和插入排序谁更快?

插入排序更快

2.1.7  对于逆序数组,选择排序和插入排序谁更快?

选择排序更快

为什么?看完代码后,再解释


一、插入排序的代码

package test;

import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;

public class Insertion {
	public static void sort(Comparable[] a){
		for(int i=1; i<a.length; i++){
			for(int j=i; j>0 && less(a[j], a[j-1]); j--){
				exch(a, j, j-1);
			}
		}
	}
	
	private static boolean less(Comparable v, Comparable w){
		return v.compareTo(w) < 0;
	}
	
	private static void exch(Comparable[] a, int i, int j){
		Comparable t = a[i];
		a[i] = a[j];
		a[j] = t;
	}
	
	private static void show(Comparable[] a){
		for(int i=0; i<a.length; i++){
			StdOut.print(a[i] + " ");
		}
		StdOut.println();
	}
	
	public static boolean isSorted(Comparable[] a){
		for(int i=1; i<a.length; i++){
			if(less(a[i], a[i-1])) return false;
		}
		return true;
	}
	
	public static void main(String[] args){
		String[] a = In.readStrings();
		sort(a);
		assert isSorted(a);
		show(a);
	}	
}

二、选择排序的代码

package test;

import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;

public class Selection {
	public static void sort(Comparable[] a){
		int N = a.length;
		for(int i=0; i<N; i++){
			int min = i;
			for(int j=i+1; j<N; j++){
				if(less(a[j], a[min])) min = j;
			}
			exch(a, i, min);
		}
	}
	
	private static boolean less(Comparable v, Comparable w){
		return v.compareTo(w) < 0;
	}
	
	private static void exch(Comparable[] a, int i, int j){
		Comparable t = a[i];
		a[i] = a[j];
		a[j] = t;
	}
	
	private static void show(Comparable[] a){
		for(int i=0; i<a.length; i++){
			StdOut.print(a[i] + " ");
		}
		StdOut.println();
	}
	
	public static boolean isSorted(Comparable[] a){
		for(int i=1; i<a.length; i++){
			if(less(a[i], a[i-1])) return false;
		}
		return true;
	}
	
	public static void main(String[] args){
		String[] a = In.readStrings();
		sort(a);
		assert isSorted(a);
		show(a);
	}
}

三、算法时间比较的代码

package test;

import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.Stopwatch;

public class SortCompare {
	public static double time(String alg, Double[] a){
		Stopwatch timer = new Stopwatch();
		if(alg.equals("Insertion")) Insertion.sort(a);
		if(alg.equals("Selection")) Selection.sort(a);
		/*if(alg.equals("Shell")) Shell.sort(a);
		if(alg.equals("Merge")) Merge.sort(a);
		if(alg.equals("Quick")) Quick.sort(a);
		if(alg.equals("Heap")) Heap.sort(a);*/
		return timer.elapsedTime();
	}
	
	public static double timeRandomInput(String alg, int N, int T){
		//使用算法alg,将T个长度为N的随机数组排序,所花的时间
		double total = 0.0;
		Double[] a = new Double[N];
		for(int t = 0; t < T; t++){
			//进行一次测试(生成一个数组并排序)
			for(int i=0; i<N; i++){
				a[i] = StdRandom.uniform();
			}
			total += time(alg,a);
		}
		return total;
	}
	
	public static double timeEqualInput(String alg, int N, int T){
		//使用算法alg, 将T个长度为N的数值全部相等的数组排序,所花的时间
		double total = 0.0;
		Double[] a = new Double[N];
		for(int i=0; i<N; i++){ 
			//由于数组元素都相等,即使排序后,也相等,所以只赋值一次
			a[i] = 1.0;
		}
		for(int t=0; t <T; t++){
			total += time(alg, a);
		}
		return total;
	}
	
	public static double timeInverseInput(String alg, int N, int T){
		//使用算法alg,将T个长度为N的逆序数组排序,所花的时间
		double total = 0.0;
		Double[] a = new Double[N];
		for(int t=0; t<T; t++){
			for(int i=0; i<N; i++){
				a[i] = 1.0 * (N-i);
			}
			total += time(alg, a);
		}
		return total;
	}
	
	public static void main(String[] args) {
		String alg1 = StdIn.readString();
		String alg2 = StdIn.readString();
		int N = StdIn.readInt();
		int T = StdIn.readInt();
		// 数组元素随机的情况下,插入排序快于选择排序
		double t1 = timeRandomInput(alg1, N, T);
		double t2 = timeRandomInput(alg2, N, T);
		StdOut.printf("for %d random Doules\n  %s is", N, alg1);
		StdOut.printf(" %.1f times faster than %s\n", t2/t1, alg2);
		
		// 数组元素都相等的情况下,插入排序快于选择排序
		double t3 = timeEqualInput(alg1, N, T);
		double t4 = timeEqualInput(alg2, N, T);
		StdOut.printf("for %d equal Doules\n  %s is", N, alg1);
		StdOut.printf(" %.1f times faster than %s\n", t4/t3, alg2);
		
		//数组元素逆序的情况下,插入排序慢于选择排序
		double t5 = timeInverseInput(alg1, N, T);
		double t6 = timeInverseInput(alg2, N, T);
		StdOut.printf("for %d inverse Doules\n  %s is", N, alg1);
		StdOut.printf(" %.1f times faster than %s\n", t6/t5, alg2);
	}
}

四、运行
算法时间比较的代码SortCompare.java进行比较

控制台输入: Insertion Selection 1000 100

输出结果(每个人电脑,每次结果都不同,不要慌):

Insertion Selection 1000 100
for 1000 random Doules
  Insertion is 1.3 times faster than Selection
for 1000 equal Doules
  Insertion is 213.0 times faster than Selection
for 1000 inverse Doules
  Insertion is 0.9 times faster than Selection


五、解释

1、为什么所有的主键都相同时,插入排序更快?

数组元素都相同时

插入排序,比较次数N-1,交换次数0

选择排序,比较次数N(N-1)/2,交换次数0


2、为什么对于逆序数组,选择排序更快?

数组逆序时

插入排序,由于逆序对有N(N-1)/2对,所以交换次数是N(N-1)/2。比较次数大于等于交换次数,小于等于

交换次数+N-1。

选择排序,不管输入是怎样的,比较次数都是N(N-1)/2。此时交换次数为N-1。


    原文作者:排序算法
    原文地址: https://blog.csdn.net/qq_18433441/article/details/77963324
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞