冒泡排序

冒泡排序

​ 想必只要是接触过算法的同学,都必听过冒泡排序这四个大字,哈哈。可以说是排序算法中最简单,最基础的一种。其名字的由来正是因为元素在整个排序过程就像碳酸饮料中的气泡一点一点浮上水面,所以称之为冒泡排序(Bubble Sort)。

过程

​ 冒泡排序的整个过程用一句话就可以总结(我们这里假设排好序的序列是从小到打的顺序):

遍历序列N次,每次遍历的过程中,如果左边的元素大于右边的元素,那么就将他们交换。

接下来我们举一个具体例子说明:

在这里插入图片描述

现在有上述一个无序序列,我们通过冒泡排序将其排列成从左向右从小到大的有序序列。第一次遍历,用来确定整个序列中最大的元素的位置。

拿9,8两个元素进行比较,由于9 > 8 所以他们进行交换后再进行指针后移:

在这里插入图片描述

然后继续将指针指向的位置上的元素和其后面相邻元素相比较,此时9 > 7,所以我们将其互换位置后再进行指针后移:

在这里插入图片描述

此时依旧拿当前指针指向的元素和其后面相邻元素相比较,此时9 > 6 ,所以我们将 9,6交换位置后再进行指针后移:

在这里插入图片描述

接下来依旧是重复之前的动作,即拿当前指针指向的元素和其后面相邻的元素相比较,此时9 > 5 ,所以我们将9,5交换位置后再进行指针后移:

在这里插入图片描述

此时已经到达了序列的最尾端,所以第一次遍历结束,而在遍历结束后,确定了9这一元素的位置。

总结一下上面遍历过程:如果arr[i] > arr[i + 1]则将两个元素交换然后指针后移,反之则只将指针后移后继续判断。

上面是一个遍历过程,确定了序列中最大值的最终位置,我们可以将剩下的问题看成一个子问题,将下图的序列排序成一个从小到大的有序序列,那么我们依旧可以按照上面提到的遍历方式去确定这个序列中的最大值的位置。

在这里插入图片描述

对上图的无序序列执行一遍遍历过程之后,得到的序列如下:

在这里插入图片描述

此时我们再将问题分解成一个子问题,即对序列7,6,5进行排序。这样一直分解下去最终问题缩小到最小就是:只剩下一个元素5,对其进行排序,那么这个时候也就确定了起初整个序列中所有元素的位置,也就得到了一个有序序列:5,6,7,8,9。

代码实现

我们现在对以上思路使用代码去落地实现:

1.遍历数组N次去确定N个元素的位置,可以使用for循环;

2.在每次遍历中,要从前向后比较每个位置的元素,所以还需要一个for循环,所以为双重循环;

3.指针则使用for循环中的遍历变量作为指针。

Java语言实现

public void bubbleSort(int[] arr) {
    if (arr == null || arr.length < 2)
        return;
    //外层for控制每次遍历的终止点 即内层循环最终确定的元素的位置
    for (int end = arr.length - 1; end > 0; end--) {
        //内层for用于比较和交换
        for (int i = 0; i < end; i++) {
            if (arr[i] > arr[i + 1])
                swap(arr, i, i + 1);
        }
    }
}

其中swap()函数是为了代码看上去简洁而封装的一个交换数组内两个位置上的元素的函数,具体代码如下:

public void swap(int[] arr, int p1,int p2){
    int temp = arr[p1];
    arr[p1] = arr[p2];
    arr[p2] = temp;
}

Golang语言实现

func BubbleSort(arr []int) {
	if len(arr) == 0 {
		return
	}
	for end := len(arr) - 1; end > 0; end-- {
		for i := 0; i < end; i++ {
			if arr[i] > arr[i+1] {
				swap(arr,i,i + 1)
			}
		}
	}
}

swap()函数代码如下:

func Swap(arr []int,i, j int) {
	temp := arr[i]
	arr[i] = arr[j]
	arr[j] = temp
}

优化冒泡排序

我们看一个具体的例子,对于一下序列进行冒泡排序:

在这里插入图片描述

对其进行一次冒泡后序列顺序如下:

在这里插入图片描述

第二次排序过后顺序如下:

在这里插入图片描述

第三次排序过后顺序如下:

在这里插入图片描述

第四次排序过后顺序如下:

在这里插入图片描述

第五次排序过后顺序如下:

在这里插入图片描述

此时整个序列已经是有序的了,按照我们之前的冒泡排序代码的话,依旧会向下执行,因为要遍历N = 7次,现在只遍历了5次。此时,我们是可以对其进行优化的。

之前代码进入第六次排序,也就是第六次进入外层循环时后,接下来进入内层循环里的判断代码:

 if (arr[i] > arr[i + 1]){
    ......
 }

因为此时序列已经有序,所以不会进入此if。那么我们就可以对之前代码进行优化。**思路:如果某次遍历整个过程中没有进入if那么说明此时序列已经有序,我们就没有必要再向下执行。**在这里我们加入标记位对其进行判断:

优化过后的代码

Java版本

public void bubbleSort2(int[] arr) {
    if (arr == null || arr.length < 2)
        return;
    for (int end = arr.length - 1; end > 0; end--) {
        boolean flag = true;
        for (int i = 0; i < end; i++) {
            if (arr[i] > arr[i + 1]) {
                swap(arr, i, i + 1);
                flag = false;
            }
        }
        if (flag)
            break;
    }
}

Golang版本

func BubbleSort(arr []int) {
	if len(arr) == 0 {
		return
	}
	for end := len(arr) - 1; end > 0; end-- {
		flag := true
		for i := 0; i < end; i++ {
			if arr[i] > arr[i+1] {
				Swap(arr,i,i + 1)
				flag = false
			}
		}
		if flag {
			break
		}
	}
}

至此,冒泡排序已经讲解完毕。如有不同,可以公众号私信作者,谢谢阅读。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值