java排序算法笔记之O(n²)级别算法(冒泡排序,选择排序,插入排序)

之前一直有学习java算法,不过没有系统的进行归纳和整理,今天算是下定决心,开始对之前了解的算法进行归纳总结。

有一些初学者朋友会问O(n²)是什么意思,首先,我们先了解一下O(n)是什么意思。

O(n)不是算法,它是一个函数,是一个表征算法时间复杂度的一个函数。

计算机科学中,算法的时间复杂度是一个函数,它定性描述了该算法的运行时间。这是一个关于代表算法输入值的字符串的长度的函数。时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。

使用这种方式时,时间复杂度可被称为是渐近的,它考察当输入值大小趋近无穷时的情况。

算法其实分时间复杂度和空间复杂度,这里我们先了解时间复杂度。

首先我们先准备一个混乱的数组     

int[] array = { 0, 2, 8, 9, 5, 7, 6, 1, 3 };

    public static int[] selSort(int[] array) {
		int minValueSub = 0;
		for (int i = 0; i < array.length; i++) {
			minValueSub = i;
			for (int j = i + 1; j < array.length; j++) {
				if (array[minValueSub] > array[j]) {
					minValueSub = j;
				}
			}
			if (minValueSub != i) {
				int tmp = array[i];
				array[i] = array[minValueSub];
				array[minValueSub] = tmp;
			}
			System.out.println("排序次数:"+i);
			display(array);
		}
		return array;
	}

    public static void selSortDis() {
		int[] array = { 0, 2, 8, 9, 5, 7, 6, 1, 3 };
		System.out.println("未排序数组顺序为:");
		display(array);
		array = selSort(array);
		System.out.println("经过选择排序后的数组顺序为:");
		display(array);
	}

    public static void display(int[] array) {
		for (int i = 0; i < array.length; i++) {
			System.out.print(array[i] + " ");
		}
		System.out.println();
	}

	public static void main(String[] args) {
		selSortDis();
	}

 

接下来我们先说一下冒泡排序,在了解冒泡的时候我会说明O(n²)是怎么得来的:

这个名词的由来很好理解,一般河水中的冒泡,水底刚冒出来的时候是比较小的,随着慢慢向水面浮起会逐渐增大,这物理规律我不作过多解释,大家只需要了解即可。

  冒泡算法的运作规律如下:

  ①、比较相邻的元素。如果第一个比第二个大,就交换他们两个。

  ②、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数(也就是第一波冒泡完成)。

  ③、针对所有的元素重复以上的步骤,除了最后一个。

  ④、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

废话不多说,先上代码:

	public static int[] bubbleSort(int[] array) {
		for (int i = 0; i < array.length; i++) {
			for (int j = i + 1; j < array.length; j++) {
				if (array[i] > array[j]) {
					int tmp = array[i];
					array[i] = array[j];
					array[j] = tmp;
				}
			}
			System.out.println("排序次数:"+i);
			display(array);
		}
		return array;
	}

	public static void bubbleSortDis() {
		int[] array = { 0, 2, 8, 9, 5, 7, 6, 1, 3 };
		// 未排序数组顺序为
		System.out.println("未排序数组顺序为:");
		display(array);
		array = bubbleSort(array);
		System.out.println("经过冒泡排序后的数组顺序为:");
		display(array);
	}

	// 遍历显示数组
	public static void display(int[] array) {
		for (int i = 0; i < array.length; i++) {
			System.out.print(array[i] + " ");
		}
		System.out.println();
	}

	public static void main(String[] args) {
		bubbleSortDis();
	}

 

通过代码可以看到,冒泡排序的主体是两个for循环,而每轮比较的次数为(n-1),(n-2)...1。

总共的次数相当于1+2+...+(n-1)次,就是n*(n-1)/2,由于n大到一定程度时其他参数的大小并不重要,运算次数几乎只看n*n的大小,所以叫做O(n²)级别的算法。

 

有了冒泡排序的基础,接下来我们看一下选择排序:

选择排序是每一次从待排序的数据元素中选出最小的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

  分为三步:

  ①、从待排序序列中,找到关键字最小的元素

  ②、如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换

  ③、从余下的 N - 1 个元素中,找出关键字最小的元素,重复(1)、(2)步,直到排序结束

接下来我们看一下选择排序的代码:

	public static int[] selSort(int[] array) {
		int minValueSub = 0;
		for (int i = 0; i < array.length; i++) {
			minValueSub = i;
			for (int j = i + 1; j < array.length; j++) {
				if (array[minValueSub] > array[j]) {
					minValueSub = j;
				}
			}
			if (minValueSub != i) {
				int tmp = array[i];
				array[i] = array[minValueSub];
				array[minValueSub] = tmp;
			}
			System.out.println("排序次数:"+i);
			display(array);
		}
		return array;
	}

	public static void selSortDis() {
		int[] array = { 0, 2, 8, 9, 5, 7, 6, 1, 3 };
		System.out.println("未排序数组顺序为:");
		display(array);
		array = selSort(array);
		System.out.println("经过选择排序后的数组顺序为:");
		display(array);
	}
	// 遍历显示数组
	public static void display(int[] array) {
		for (int i = 0; i < array.length; i++) {
			System.out.print(array[i] + " ");
		}
		System.out.println();
	}
    public static void main(String[] args) {
		selSortDis();
	}

由此可以看出,选择排序做了和冒泡排序一样多次比较,总共比较次数为n*(n-1)/2,不过选择排序对数组的操作次数更少,每次排序只是把两个下标的值交换,所以相对速度是比冒泡排序要快的。

最后我们看一下插入排序,直接插入排序基本思想是每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止。我们今天就先不管别的插入排序,先讲一下直接插入排序。

具体做法就是每次拿出>1数量的数组的值进行比较,最开始拿出两个,依次累加,直接上代码:

    public static int[] insertSort(int[] array) {
		for (int i = 0; i < array.length; i++) {
			while (i > 0 && array[i - 1] > array[i]) {
				int tmp = array[i - 1];
				array[i - 1] = array[i];
				array[i] = tmp;
				i--;
			}
		}
		return array;
	}
	public static void display(int[] array) {
		for (int i = 0; i < array.length; i++) {
			System.out.print(array[i] + " ");
		}
		System.out.println();
	}
	public static void insertSortDis() {
		int[] array = { 0, 2, 8, 9, 5, 7, 6, 1, 3 };
		System.out.println("未排序数组顺序为:");
		display(array);
		array = insertSort(array);
		System.out.println("经过插入排序后的数组顺序为:");
		display(array);
	}

	public static void main(String[] args) {
		insertSortDis();
	}

在第一轮排序中,它最多比较一次,第二轮最多比较两次,一次类推,第N轮,最多比较N-1次。因此有 1+2+3+...+N-1 = N*(N-1)/2。

假设在每一轮排序发现插入点时,平均只有全体数据项的一半真的进行了比较,我们除以2得到:N*(N-1)/4。用大O表示法大致需要需要 O(N2) 时间级别。

 

总结一下:

上面讲的三种排序,冒泡、选择、插入用大 O 表示法都需要 O(N2) 时间级别。一般不会选择冒泡排序,虽然冒泡排序书写是最简单的,但是平均性能是没有选择排序和插入排序好的。

  选择排序把交换次数降低到最低,但是比较次数还是挺大的。当数据量小,并且交换数据相对于比较数据更加耗时的情况下,可以应用选择排序。

  在大多数情况下,假设数据量比较小或基本有序时,插入排序是三种算法中最好的选择。

最后把全部代码粘出来大家看一下:

package com.zy.test;

public class Sort {
    public static int[] insertSort(int[] array){
    	for (int i = 0; i < array.length; i++) {
			while(i>0&&array[i-1]>array[i]){
					int tmp = array[i];
					array[i-1] = array[i];
					array[i-1] = tmp;
					i--;
			}
		}
        return array;
    }
    
    public static int[] bubbleSort(int[] array){
        for (int i = 0; i < array.length; i++) {
			for (int j = i+1; j < array.length; j++) {
				if(array[i]>array[j]){
					int tmp = array[i];
					array[i] = array[j];
					array[j] = tmp;
				}
			}
		}
        return array;
    }
    
    public static int[] selSort(int[] array){
        int minValueSub = 0;
        for (int i = 0; i < array.length; i++) {
        	minValueSub = i;
			for (int j = i+1; j < array.length; j++) {
				if(array[minValueSub] > array[j]){
					minValueSub = j;
				}
			}
			if(minValueSub!=i){
				int tmp = array[i];
				array[i] = array[minValueSub];
				array[minValueSub] = tmp;
			}
		}
        return array;
    }
    
     
    //遍历显示数组
    public static void display(int[] array){
        for(int i = 0 ; i < array.length ; i++){
            System.out.print(array[i]+" ");
        }
        System.out.println();
    }
     
    public static void bubbleSortDis(){
    	int[] array = {0,2,8,9,5,7,6,1,3};
        //未排序数组顺序为
        System.out.println("未排序数组顺序为:");
        display(array);
        array = bubbleSort(array);
        System.out.println("经过插入冒泡排序后的数组顺序为:");
        display(array);
    }
    
    public static void selSortDis(){
    	int[] array = {0,2,8,9,5,7,6,1,3};
        //未排序数组顺序为
        System.out.println("未排序数组顺序为:");
        display(array);
        array = selSort(array);
        System.out.println("经过选择排序后的数组顺序为:");
        display(array);
    }
    
    public static void insertSortDis(){
    	int[] array = {0,2,8,9,5,7,6,1,3};
        //未排序数组顺序为
        System.out.println("未排序数组顺序为:");
        display(array);
        array = selSort(array);
        System.out.println("经过插入排序后的数组顺序为:");
        display(array);
    }
    
    public static void main(String[] args){
    	bubbleSortDis();
    	selSortDis();
    	insertSortDis();
    }
 
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值