手撕排序算法:冒泡排序


冒泡排序(Bubble Sort)是一种简单的排序算法,通过多次比较和交换相邻的元素,将数组
中的元素按升序或降序排列。

1.算法思想

冒泡排序的基本思想是:每次遍历数组,比较相邻的两个元素,如果它们的顺序错误,就将它
们交换,直到数组中的所有元素都被遍历过。
具体的算法步骤如下:
第一步、遍历数组的第一个元素到最后一个元素。
第二步、对每一个元素,与其后一个元素进行比较。
第三步、如果顺序错误,就将它们交换。
重复上述步骤,直到数组中的所有元素都被遍历过至少一次。

2.冒泡排序具体过程

首先需要将「第一个元素」和「第二个元素」进行「比较」,如果前者大于后者,则进行「交
换」,
然后再比较「第二个元素」和「第三个元素」,以此类推,直到「最大的那个元素」被移动
到「最后的位置」。
然后,进行第二轮「比较」,直到「次大的那个元素」被移动到「倒数第二的位置」
最后,经过一定轮次的「比较」和「交换」之后,一定可以保证所有元素都是「升序」排列
的。

3.算法分析

3.1时间复杂度

我们假设「比较」和「交换」的时间复杂度为O(1)(为什么这里说假设,因为有可能要「比
较」的两个元素本身是数组,并且是不定长的,所以只有当系统内置类型,我们才能说这两个操
是0(1)的)。
「冒泡排序」中有两个嵌套循环。
外循环正好运行一1次迭代。但内部循环运行变得越来越短:
当i=0,内层循环n一1次「比较」操作。
英雄哪里出来182585442552122
当i=1,内层循环n一2次「比较」操作。
当i=2,内层循环n一3次「比较」操作。
当i=n一2,内层循环1次「比较」操作。
当i=n一1,内层循环0次「比较」操作。
英雄哪里出来海豚知通552122
因此,总「比较」次数如下:
总的时间复杂度为:O(n^2)

3.2空间复杂度

由于算法在执行过程中,只有「交换」变量时候采用了临时变量的方式,而其它没有采用任何
的额外空间,所以空间复杂度为O(1)。

4.算法的优缺点

4.1算法的优点

1.简单易懂:冒泡排序的算法思想非常简单,容易理解和实现。
2.稳定排序:冒泡排序是一种稳定的排序算法,即在排序过程中不会改变相同元素的相对顺
序。

4.2算法的缺点

1.效率较低:由于需要进行多次比较和交换,冒泡排序在处理大规模数据时效率较低。
2.排序速度慢:对于大型数组,冒泡排序的时间复杂度较高,导致排序速度较慢。

5.冒泡排序优化方案

「冒泡排序」在众多排序算法中效率较低,时间复杂度为O(2)。
想象一下,当有=100000个数字。即使我们的计算机速度超快,并且可以在1秒内计算
10^8次操作,但冒泡排序仍需要大约一百秒才能完成。
但是,它的外层循环是可以提前终止的,例如,假设一开始所有数字都是升序的,那么在首轮「比较」的时候没有发生任何的「交换」,那么后面也就不需要继续进行「比较」了,直接跳出外
层循环,算法提前终止。
「改进思路」如果我们通过内部循环完全不交换,这意味着数组已经排好序,我们可以在这个
点上停止算法。

6.算法实现

void Bottle_Sort(int nums[],int numsSize) {  
    for (int i = 0; i <numsSize - 1; i++) {  
        for (int j = 0; j < numsSize - i - 1; j++) {  
            if (nums[j] > nums[j+1]) {  
                int temp = nums[j];  
                nums[j] = nums[j + 1];  
                nums[j + 1] = temp;  
            }  
        }  
    }  
}

7.实战

7.1 力扣88. 合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
**注意:**最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {  
    int i,j,num;  
    for(i=0;i<n;i++)  
    {  
        nums1[m+i]=nums2[i];  
    }  
    for(i=0;i<nums1Size-1;i++)  
    {  
        for(j=0;j<nums1Size-1-i;j++)  
        {  
            if(nums1[j]>nums1[j+1])  
            {  
                num=nums1[j];  
                nums1[j]=nums1[j+1];  
                nums1[j+1]=num;  
            }  
        }  
    }  
}

7.2力扣2148.元素计数

给你一个整数数组 nums ,统计并返回在 nums 中同时至少具有一个严格较小元素和一个严格较大元素的元素数目。

void Bottle_Sort(int nums[],int numsSize) {  
    for (int i = 0; i <numsSize - 1; i++) {  
        for (int j = 0; j < numsSize - i - 1; j++) {  
            if (nums[j] > nums[j+1]) {  
                int temp = nums[j];  
                nums[j] = nums[j + 1];  
                nums[j + 1] = temp;  
            }  
        }  
    }  
}  
int countElements(int* nums, int numsSize) {  
    Bottle_Sort(nums,numsSize);  
    int count = 0;  
    for(int i = 1; i < numsSize - 1; i++){  
        if(nums[i] != nums[0] && nums[i] != nums[numsSize - 1]){  
            count++;  
        }  
    }  
    return count;  
}

7.3力扣1046.最后一块石头的重量

有一堆石头,每块石头的重量都是正整数。
每一回合,从中选出两块最重的石头,然后将它们一起粉碎。假设石头的重量分别为x和y,且x<=y。那么粉碎的可
能结果如下:

  • 如果x=y,那么两块石头都会被完全粉碎;
  • 如果x!=y,那么重量为x的石头将会完全粉碎,而重量为y的石头新重量为y-x。
    最后,最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下,就返回0。
void Bottle_Sort(int nums[],int numsSize) {  
    for (int i = 0; i <numsSize - 1; i++) {  
        for (int j = 0; j < numsSize - i - 1; j++) {  
            if (nums[j] > nums[j+1]) {  
                int temp = nums[j];  
                nums[j] = nums[j + 1];  
                nums[j + 1] = temp;  
            }  
        }  
    }  
}  
int lastStoneWeight(int* stones, int stonesSize) {  
    while(stonesSize > 1){  
        Bottle_Sort(stones,stonesSize);  
        int v = stones[stonesSize - 1] - stones[stonesSize - 2];  
        stonesSize -=2;  
        if(v != 0 || stonesSize == 0){  
            stones[stonesSize] = v;  
            stonesSize++;  
        }  
    }  
    return stones[0];  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写代码的大学生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值