算法(第四版)2.1初级排序算法

算法(第四版)2.1初级排序算法

一、算法2.1 选择排序

1.算法思想

  1. 找到数组元素中最小的元素
  2. 将它与数组中第一个元素互换(如果第一个元素最小,就和自己互换)
  3. 在生下的元素中找到最小的元素,与数组中第二个元素交换位置
  4. 以此类推,直至将整个数组排序

2.命名原因

​ 不断地选择剩余元素之中的最小者

3.代码实现

public class Selection {
	public static void sort(Comparable[] a) {
		// 将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);		
		}
	}
	// v < w 返回true
	private static boolean less(Comparable v, Comparable w) {
		return v.compareTo(w) < 0;
	}
	// 交换a[i]和a[j]的位置
	private static void exch(Comparable[] a, int i, int j) {
		Comparable t = a[i];
		a[i] = a[j];
		a[j] = t;
	}
	// 在单行打印数组
	public static void show(Comparable[] a) {
		for (int i = 0; i < a.length - 1; i++) {
			System.out.print(a[i]+" ");
		}
		System.out.print(a[a.length - 1]);
		System.out.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;
	}
}
import java.util.Scanner;
import java.util.ArrayList;

public class Test {
	public static void main(String[] args) {
		ArrayList<String> array = new ArrayList<String>();
		Scanner sc1 = new Scanner(System.in);
		Scanner sc2 = new Scanner(sc1.nextLine());
		while(sc2.hasNext()) {
			array.add(sc2.next());
		}
		Selection sel = new Selection();
		String[] a = new String[array.size()];
		for (int i = 0; i < a.length; i++) {
			a[i] = array.get(i);
		}
		sel.sort(a);
		assert sel.isSorted(a);
		sel.show(a);
		
	}
}

bed bug yes zoo all bad yet
all bad bed bug yes yet zoo

4.算法分析

​ 对于长度为N的数组

  • 需要大约 N 2 / 2 N^2/2 此比较
    • 具体为$ (N-1)+(N-2)+···2+1=N(N-1)/2$
  • 需要 N N 次交换

5.算法特点

  • 运行时间和输入无关
    • 无论数组一开始有序或者随机排列,运行时间不变
  • 数据移动是最少的
    • 交换次数和数组大小成线性关系

二、算法2.2 插入排序

1.算法思想

  1. 先将数组第一个元素不动
  2. 从第二个元素开始,将此元素与前一个元素比较
  3. 若此元素较小则交换两个元素位置,继续与前一个元素比较直至第一个元素
  4. 以此类推,直至将整个数组排序

2.命名原因

​ 和理牌一样,新抽取的牌往里面插入适当位置

3.代码实现

public class Insertion {
	public static void sort(Comparable[] a) {
		// 将a[]按升序排列
		int N = a.length;
		for (int i = 0; i < N; i++) {
			// 将a[i] 插入到a[i-1] a[i-2] a[i-3]···中
			for(int j = i; j>0 && less(a[j], a[j-1]); j--)
				exch(a, j, j-1);
		}
	}
	// v < w 返回true
	private static boolean less(Comparable v, Comparable w) {
		return v.compareTo(w) < 0;
	}
	// 交换a[i]和a[j]的位置
	private static void exch(Comparable[] a, int i, int j) {
		Comparable t = a[i];
		a[i] = a[j];
		a[j] = t;
	}
	// 在单行打印数组
	public static void show(Comparable[] a) {
		for (int i = 0; i < a.length - 1; i++) {
			System.out.print(a[i]+" ");
		}
		System.out.print(a[a.length - 1]);
		System.out.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;
	}
}
import java.util.Scanner;
import java.util.ArrayList;

public class Test {
	public static void main(String[] args) {
		ArrayList<String> array = new ArrayList<String>();
		Scanner sc1 = new Scanner(System.in);
		Scanner sc2 = new Scanner(sc1.nextLine());
		while(sc2.hasNext()) {
			array.add(sc2.next());
		}
		Insertion ins = new Insertion();
		String[] a = new String[array.size()];
		for (int i = 0; i < a.length; i++) {
			a[i] = array.get(i);
		}
		ins.sort(a);
		//assert sel.isSorted(a);
		ins.show(a);
		
	}
}

bed bug yes zoo all bad yet
all bad bed bug yes yet zoo

4.算法分析

​ 对于长度为N的数组

  • 平均情况:大约需要 N 2 / 4 N^2/4 次比较 N 2 / 4 N^2/4 次交换
  • 最坏情况:需要 N 2 / 2 N^2/2 次比较 N 2 / 2 N^2/2 次交换
    • 所有元素都需要移动位置(逆序数组)
    • 1 + 2 + + ( N 2 ) + ( N 1 ) 1+2+···+(N-2)+(N-1)
  • 最好情况:需要 N 1 N-1 次比较 0 0 次交换
    • 所有元素都不需要移动位置(有序数组)
    • $ \overbrace{1+1+···+1}^{N-1} $

5.插入排序的适合情形

倒置:数组中两个顺序颠倒的元素

EXAMPLE中有:E-A,X-A,X-M,X-P,X-L,X-E,M-L,M-E,P-L,P-E,L-E共11对倒置

部分有序数组:数组中倒置的数量小于数组大小的某个倍数

几种典型的部分有序数组

  • 数组中每个元素距离它的最终位置都不远
  • 一个有序的大数组接一个小数组
  • 数组中只有几个元素的位置不正确

插入排序需要的交换操作和数组中倒置的数量相同,需要比较的次数大于等于倒置的数量,小于等于倒置的数量加上数组的大小再减一

最快情况:比较次数=倒置数量= N ( N 1 ) / 2 N(N-1)/2

最好情况:比较次数=倒置数量+数组大小-1= N 1 N-1

三、算法2.3 希尔排序

1.算法思想

  • 使数组任意间隔为h的元素都是有序的
  • (改进的插入排序)交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序

2.代码实现

public class Shell {
	public static void sort(Comparable[] a) {
		// 将a[]按升序排列
		int N = a.length;
		int h = 1;
		while(h < N/3)
			// h可以为1,4,13,40 ···
			h = 3*h + 1;
		while(h >= 1) {
			for (int i = 0; i < N; i++) {
				// 将a[i]插入a[i-h],a[i-2*h],a[i-3*h]···
				for (int j = i; j>=h && less(a[j], a[j-h]); j -= h) 
					exch(a, j, j-h);
			}
			h = h/3;
		}
	}
	// v < w 返回true
	private static boolean less(Comparable v, Comparable w) {
		return v.compareTo(w) < 0;
	}
	// 交换a[i]和a[j]的位置
	private static void exch(Comparable[] a, int i, int j) {
		Comparable t = a[i];
		a[i] = a[j];
		a[j] = t;
	}
	// 在单行打印数组
	public static void show(Comparable[] a) {
		for (int i = 0; i < a.length - 1; i++) {
			System.out.print(a[i]+" ");
		}
		System.out.print(a[a.length - 1]);
		System.out.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;
	}
}
import java.util.Scanner;
import java.util.ArrayList;

public class Test {
	public static void main(String[] args) {
		ArrayList<String> array = new ArrayList<String>();
		Scanner sc1 = new Scanner(System.in);
		Scanner sc2 = new Scanner(sc1.nextLine());
		while(sc2.hasNext()) {
			array.add(sc2.next());
		}
		Shell sh = new Shell();
		String[] a = new String[array.size()];
		for (int i = 0; i < a.length; i++) {
			a[i] = array.get(i);
		}
		sh.sort(a);
		sh.show(a);
		
	}
}

bed bug yes zoo all bad yet
all bad bed bug yes yet zoo

3.算法分析

  • 希尔排序算法性能分析复杂(超过本书范围)(待查阅)
  • 已知最坏情况下比较次数和 N 3 / 2 N^{3/2} 成正比
  • 使用1,4,13,40,···的希尔排序所需的比较次数不会超过N的若干倍数乘以递增序列的长度
发布了5 篇原创文章 · 获赞 0 · 访问量 74

猜你喜欢

转载自blog.csdn.net/qq_41984731/article/details/104179794