算法基础——冒泡排序,选择排序和插入排序

    冒泡排序:

    从a[index=0]开始比较a[0]和a[1],按照程序给定判断是否交换位置,然后a[1]和a[2]比较,一直到a[max]。此时a[max]一定是要求的最大或者最小,下一次循环不需要再比较,所以length-i。

                 5,4,3,2,1

第一次:   4,3,2,1,5

第二次:      3,2,1,4,5

第三次:    2,1,3,4,5

第四次:      1,2,3,4,5

		public static void main(String[] args) {
			int a[] = {-19, 3, 5, 0,902};
			for (int i = 0; i < a.length; i++) {
				for (int j = 1; j < a.length - i; j++) {
					if (a[j] > a[j + 1]) {
						int b = a[j];
						a[j] = a[j + 1];
						a[j + 1] = b;
					}
				}
			}
			for (int i = 0; i < a.length; i++) {
				System.out.print(" "+a[i]);
			}
		}

    比较次数:(n-1)+(n-2)+(n-3)+(n-4)+...+1=(n-1)*n/2
    交换次数:约为N^2/4
    由于常数不算在大O表示法,可以忽略2和4,并且认为冒泡排序与逆行需要O(N^2)时间级别
    无论何时,发现一个循环嵌套一个循环(如冒泡排序),都可以怀疑运行时间为O(N^2)级。外层循坏执行N次,内层循环执行N次或者递减N次或者几分之N次,以为这大约执行n^2次基本操作,都可以视为O(N^2)

选择排序:

    对冒泡排序进行了改进,虽然让交换次数降低到N次,但是比较次数依旧是O(N^2)。改变了引用位置,实际对象的位置并没有发生改变。
    取出第一个数a[0]假设最小,与后面所有的数依次比较,根据代码判断是否交换,交换(角标)则改变了(角标)重新声明了此时的最小或最大数,并没有改变数字的位置,直到完成内层循环,将此时的最大或者最小和外层循环假定最大或者最小交换位置。因为完成一次循环以后已经确定最前为最大或最小值,不需要在进入排序,所以内层循环为int j=i+1;   

	public static void main(String[] args) {
		int a[] = { 0, 3,  5, 4,20};
		for (int i = 0; i < a.length; i++) {
			int temp = i;
			for (int j = i + 1; j < a.length; j++) {
				if (a[temp] < a[j]) {
					temp = j;
				}
			}
			int b = a[temp];
			a[temp] = a[i];
			a[i] = b;
		}
		for (int i = 0; i < a.length; i++) {
			System.out.print(" " + a[i]);
		}
	}

    虽然选择排序和冒泡排序都需要进行O(N^2)次比较,但选择排序只需要交换N次。
    对于 10 个数据项,需要 45 次比较。然而,10 个数据项只需要少于 10次交换。对于 100 个数据项,需要 4950 次比较,但只进行了不到 100 次的交换。N 值很大时,比较的次数是主要的,所以结论是选择排序和冒泡排序一样运行了 O(N2)时间。但是,选择排序无疑更快,因为它进行的交换少得多。当 N 值较小时,特别是如果交换的时间级比比较的时间级大得多时,选择排序实际上是相当快的。

插入排序:

    插入排序虽然比冒泡排序和选择排序更快,但是依旧是0(N^2)级。
    将数据插入到数组中,和前面的比较,根据代码判断交换位置。往前比较时条件为(j>0)。

	public static void main(String[] args) {
		int[] a = { 6, 13, -8, 5, 0, 74 ,7384,3789532,-42323};
		int b;
		for(int i = 1;i<a.length;i++) {
			for(int j = i;j>0;j--) {
				if(a[j]<a[j-1]) {//假设插入的数比前面的数小
					b = a[j];
					a[j] = a[j-1];
					a[j-1] = b;
				}
			}
		}
		for (int i = 0; i < a.length; i++) {
			System.out.print(" " + a[i]);
		}
	}

    在第一次排序中最多比较一次,第二次排序中最多比较两次,因此比较次数最多为1+2+...+(N-1)=N*(N-1)/2次。但是在在每次发现从插入点之前,平均只比较了一半的数,总共N*(N-1)/4次。所以当数据基本有序的时候,插入排几乎只需要O(N)的时间。

    然而,对于逆序的数据排序,每次移动和比较都会执行,所以不比冒泡排序快。

猜你喜欢

转载自blog.csdn.net/weixin_42621338/article/details/82053235