排序--Bubble的优化和性能(算法时间、空间复杂度、稳定性)分析

article/2025/2/28 19:41:27

 

一、算法基本思想

(1)基本思想

冒泡排序的基本思想就是:从无序序列头部开始,进行两两比较,根据大小交换位置,直到最后将最大(小)的数据元素交换到了无序队列的队尾,从而成为有序序列的一部分;下一次继续这个过程,直到所有数据元素都排好序。

算法的核心在于每次通过两两比较交换位置,选出剩余无序序列里最大(小)的数据元素放到队尾。

二、算法实现

void BubbleSort(int *arr, int len)
{assert(arr);int i = 0;int j = 0;int tmp = 0;for (i = 0; i < len - 1; i++)     //n-1趟{for (j = 0; j < len -i- 1; j++)       {if (arr[j]>arr[j + 1]){tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}

    冒泡排序还有三种优化方式:(以下都是以升序为例)

例如要排序下面这组数据: 0  1  2  3  4  5  6   7  9  8

     经过第一趟冒泡排序已经有序了,下面的几趟已经是多余的,这时我们可以加一个标志位flag,若那一趟没有交换数据,这这时已经有序,我们就可以退出排序,不必进行下来的几趟。

算法实现:
 

void BubbleSort(int *arr, int len)
{assert(arr);int i = 0;int j = 0;int flag = 0;int tmp = 0;for (i = 0; i < len - 1; i++){flag = 1;                             for (j = 0; j < len - i - 1; j++)     //每排序一趟,则必然后面有一个已经有序,可以缩小排序的范围{if (arr[j]>arr[j + 1])             //只要要交换数据,则flag就会被修改{tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;flag = 0;                   //只要还未完全有序,则修改flag为0}}if (flag)                            {break;}}
}

冒泡再次优化的方法!!!

例如要排序下面这组数据:1  4  3  2  6  7  8  9 

     经过第一趟冒泡排序比较了,发现后面数据没有交换已经有序,接下来几趟比较后面的数据已经是多余的,这时我们可以记录每一次交换的位置,下一次从第一个数据比较到最后一次交换位置即可,不必再次比较后面的数据。

算法实现:

void BubbleSort(int *arr, int len)
{assert(arr);int i = 0;int j = 0;int flag = 0;int tmp = 0;int m = 0;                  //用来记录最后一次交换的位置int k = len-1;for (i = 0; i < len - 1; i++){m = 0;flag = 1;for (j = 0; j < k; j++)       //无序区的范围只从第一个元素,到上一趟最后一次交换的位置k{if (arr[j]>arr[j + 1]){tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;flag = 0;                   m = j;}}if (flag)                          {break;}k = m;                             //将k置成最后一次交换的位置}
}

冒泡排序还有第三种优化方式:

    对下面这组这组数进行排序:2  3  4  5  6  7  8  9  10  1

     只有后面两个数据无序,前面已经有序,按照以上优化冒泡需要进行多次。这时,我们采用正反交替扫描,正着找最大值,翻着找最小值,一趟就可以使数据有序。

void BubbleSort(int *arr, int len)
{assert(arr);int i = 0;int j = 0;int flag = 0;int m = 0;       //记录最后一次交换的位置int n = 0;int k = len - 1;for (i = 0; i < len - 1; i++){m = 0;flag = 1;//正序扫描找最大值for (j = n; j < k; j++)       //无序区的范围只从第一个元素,到上一趟最后一次交换的位置k{if (arr[j]>arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;flag = 0;                    m = j;}}k = m;if (flag)             {break;}//反序扫描找最小值for (j = k; j>n; j--)       //无序区的范围只从第一个元素,到上一趟最后一次交换的位置k{if (arr[j]<arr[j - 1]){int tmp = arr[j];arr[j] = arr[j - 1];arr[j - 1] = tmp;flag = 0;                  }}n++;if (flag)                   {break;}                           //将k置成最后一次交换的位置}
}

若比较的数据不是整形是其他类型怎么处理,这是我们需要支持泛型编程。

基础知识:

void * :通用指针(无符号指针)或叫做泛型指针,它的特点有:

(1)它用于临时存储地址

(2)它不能解引用

(3)它不能进行算术运算,因为呢,它就是临时的盒子,所以呀,不能依赖它进行计算,总不可能依赖一个通用的盒子计算有   类型的数据吧

算法实现:

//4.泛型冒泡
typedef int(*PCmp)(void *vp1, void *vp2);//泛型比较
void Swap(void* vp1, void*vp2,int size)
{void* temp = malloc(size);memcpy(temp, vp1, size);memcpy(vp1, vp2, size);memcpy(vp2, temp, size);free(temp);
}
void BubbleSort(void* arr, int len, int elemsize, PCmp cmp)
{void* var1;void* var2;int k = len - 1;int m = 0;bool flag = 1;for (int i = 0; i < len - 1; ++i){for (int j = 0; j < k; ++j){var1 = (char*)arr + j*elemsize;var2 = (char*)arr + (j + 1)*elemsize;if (cmp(var1, var2)>0){Swap(var1, var2, elemsize);m = j;flag = 0;}}if (flag) break;k = m;}
}
int Cmp_int(void *vp1, void *vp2)
{return *(int *)vp1 - *(int *)vp2;
}int Cmp_str(void *vp1, void *vp2)
{return strcmp(*(char **)vp1, *(char **)vp2);
}void Test()
{int arr[] = { 3, 5, 7, 9, 0, 12, 45, 6, 78, 23, 44, 10 };BubbleSort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), Cmp_int);char *brr[] = { "abc", "aaa", "bcd", "xyz", "ccccc", "hhh" };BubbleSort(brr, sizeof(brr) / sizeof(brr[0]), sizeof(char *), Cmp_str);getchar();}
int main()
{Test();}

运行结果:

三、性能(算法时间、空间复杂度、稳定性)分析

 (1)时间复杂度

当原始序列“正序”排列时,冒泡排序总的比较次数为n-1,移动次数为0,也就是说冒泡排序在最好情况下的时间复杂度为O(n);

当原始序列杂乱无序时,冒泡排序的平均时间复杂度为O(n^2)。

(2)空间复杂度

冒泡排序排序过程中需要一个临时变量进行两两交换,所需要的额外空间为1,因此空间复杂度为O(1)。

(3)稳定性

冒泡排序在排序过程中,元素两两交换时,相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。


http://chatgpt.dhexx.cn/article/EOTWqo8p.shtml

相关文章

Git查看分支创建时间

实际应用中&#xff0c;可能需要准确知道指定分支的创建时间。 代码实例如下&#xff1a; git reflog show --dateiso mastergit reflog show --dateiso #######[Shell] 纯文本查看 复制代码 1 $ git reflog show --dateiso master 代码运行效果截图如下&#xff1a; 可以…

git怎样查看分支关系图

git log --oneline --graph --decorate --all

git中查看全部分支的命令

现在介绍一个超级实用、使用频率极高但几乎所有 Git 教程都不重视的命令 git branch -avv&#xff0c;它用来查看全部分支信息&#xff1a; 上图有三行信息&#xff0c;依次说明: 第一行&#xff0c;开头的星号表示当前所在分支&#xff0c;绿色的 master 是分支名&#xff0c…

git 命令查看分支的创建者是谁

在你的工程目录下 打开终端,输入一下命令即可 git log --oneline master | cut -d " " -f 1 | tail -1 | xargs git log 如上图所示&#xff0c; Author 就是创建者&#xff0c;Date 就是创建日期。“提交项目”这个描述是最初我创建分支的备注

git查看当前分支是基于哪个分支拉取

命令&#xff1a; git reflog show --datelocal | grep 当前分支名举例&#xff1a;比如当前分支为develop&#xff0c;那么命令如下&#xff1a; git reflog show --datelocal | grep develop查询结果如下&#xff1a; 在最后一条记录&#xff0c;可以看到信息为&#xff1…

git如何查看分支

如何查看分支 git branch -vvgit如何切换分支 git checkout branch_name查看远程分支 git branch -a查看本地分支 git branch创建分支 git branch test切换分支到test git checkout test删除本地分支 git branch -d xxxxx查看本地和远程分支 -a 前面带*号的代表你当前工…

git如何查看分支的创建人

背景: 项目初期建立了两个模块的分支,后续多模块开发结束,回看代码整理分支的时候发现以前的分支不记得是否为自己所创,为了不误删别人的分支,此时就需要知道这些分支到底是谁建立的.问题: git如何查看分支的创建人?解决: 我是使用sourceTree进行git管理, 解决这个问题核心的就…

Git查看分支从哪个分支创建的

使用命令 Git查看分支创建时间 git reflog show --dateiso <branch name> 如果是feature分支 git reflog show --dateiso feature/设备小程序 提交多的话&#xff0c;按回车滚动到最后一条 最后一条是创建时间 不过一般我们需要的是远程的&#xff0c;分支名加上or…

Git查看分支的创建人

开发小组人多的时候&#xff0c;仓库里会有跟多分支&#xff0c;需要看下某个分支具体是谁创建的。 命令&#xff1a; git for-each-ref --format%(committerdate) %09 %(authorname) %09 %(refname) | sort -k5n -k2M -k3n -k4n输出如下&#xff1a; 有个缺点是日期中的月份…

如何用git查看分支

1 首先从github&#xff0c;gitblit&#xff0c;gitee上下载的项目文件都有一个隐藏的.git文件&#xff0c;先让这个隐藏文件显示出来。在查看里将隐藏的项目勾上。 2 通过vscode打开 3 现在要查看本地仓库的分支用下面这个命令 git branch 4 现在查看远程仓库的分支是在哪个…

【Git】 常用命令速查

一、 Git 常用命令速查 git branch 查看本地所有分支 git status 查看当前状态 git commit 提交 git branch -a 查看所有的分支 git branch -r 查看远程所有分支 git commit -am "init" 提交并且加注释 git remote add origin git192.168.1.119:ndshow git push o…

Git命令:查看分支、创建分支、合并分支

一、查看分支 查看的git命令如下&#xff1a; git branch 列出本地已经存在的分支&#xff0c;并且当前分支会用*标记 git branch -r 查看远程版本库的分支列表 git branch -a 查看所有分支列表&#xff08;包括本地和远程&#xff0c;remotes/开头的表示远程分支&#xff09;…

css 固定定位失效问题 position: fixed

问题&#xff1a; 今天项目做一个电梯导航&#xff0c;用到position: fixed&#xff08;固定定位&#xff09;&#xff0c;发现有定位效果&#xff0c;但是拖动滚动条会显示(会根据页面卷曲&#xff0c;遮盖) 方案&#xff1a; 找了一下原因&#xff0c;我给定位的父盒子加了…

CSS固定定位[相对浏览器] 相对定位[相对自己] 绝对定位[有relative的元素]

1基础 Fixed&#xff1a;固定定位 是相对于浏览器窗口来定位的 Absolution&#xff1a; 绝对定位&#xff1a;当没有父元素或者父元素没有进行定位的时候&#xff0c;就是固定定位&#xff0c;以浏览器为标的物 元素会脱离文档流&#xff0c;若该元素没有设置宽度&#xff0c;…

css绝对定位、相对定位、固定定位

css 定位 一、css的三种定位属性 1. 相对定位 position: relative; 元素相对于自己原来的位置&#xff0c;进行位移。 特性&#xff1a; ​ 1,不脱离文档流;其他元素不受影响 ​ 2,相对于自己的文档流上下左右定位 ​ 3,层级高于其他元素 ​ 4,使用属性:top bottom left r…

CSS定位布局详解

CSS定位布局详解 1.定位布局概述2.固定定位&#xff1a;fixed3.相对定位&#xff1a;relative4.绝对定位&#xff1a;absolute5.静态定位&#xff1a;static 1.定位布局概述 CSS定位使你可以将一个元素精确地放在页面上指定的地方。联合使用定位和浮动&#xff0c;能够创建多种…

html制作固定的菜单栏,CSS固定定位生成网页顶部导航栏实例

固定定位 position:fixed 固定定位是相对与浏览器窗口来定位, 就算页面滚动, 固定定位元素的位置不会变 固定定位元素脱离了标准文档流, 会雅盖主标准文档流里的元素 固定定位元素不再占用空间 ​ p.one { position: fixed; left: 5px; top: 5px; } ​ p.two { position: fixed…

html固定按钮相对位置,css固定定位和绝对定位的区别是什么?

CSS固定定位和绝对定位的区别是什么&#xff1f;下面本篇文章就来给大家介绍一下固定定位和绝对定位的区别。有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对大家有所帮助。 绝对定位 绝对定位即脱离文档流的定位。定位参照物为自己的父级&#xff0c…

CSS固定定位 将模块固定到版心右边

目的&#xff1a;在900*1500的版心右边设置50*150固定不随页面滚动条移动的板块 方法&#xff1a;给板块添加固定定位后先用left:50%将其定位在网页中间&#xff0c;再添加版心一半宽的外边距&#xff0c;从版心的中间移动至版心的右侧 代码如下 ​​​​​​​HTML文件&…

CSS 固定定位 position fixed

简单描述&#xff1a;固定定位是将某个元素固定在浏览器的某个确定的位置&#xff0c;不随滚动条的移动而变化&#xff1b; 注意&#xff1a;固定定位的位置是 相对当前浏览器窗口 的&#xff1b; 代码示例&#xff1a; 1.我们先在页面中输出一个标准情况下的 div 元素&…