[排序篇] 冒泡排序

目錄

一、概念

二、冒泡排序

2.1?冒泡降序(從大到小排序)

2.2?冒泡升序(從小到大排序)

三、冒泡排序應用?

總結?


一、概念

冒泡排序核心思想:每次比較兩個相鄰的元素,如果它們不符合排序規則(升序或降序)則把它們交換過來。

二、冒泡排序

2.1?冒泡降序(從大到小排序)

冒泡降序:每次比較相鄰的兩個數,如果后面的數比前面的數大,則交換這兩個數的位置。?

假設將 12 18 76 35 99?這 5 個數進行從大到小的排序(即,越小的越靠后)

如上圖所示,從左往右逐列看,5 個數總共需要遍歷 4 次(即 n - 1 次);而每列從上往下逐行看,每遍歷一次總共需要排序 n - i 次(i 代表遍歷的次數)。

1. 首先看第一列:?

1.1 第一行:比較第 1 位和第 2 位的大小,發現 12 比 18 要小,因為是降序,所以需要交換這兩個數的位置。交換之后這 5 個數的順序是 18 12 76 35 99;

1.2 第二行:比較第 2 位和第 3 位的大小,發現 12 比 76 要小,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 18 76 12 35 99;

1.3 第三行:比較第 3 位和第 4 位的大小,發現 12 比 35 要小,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 18 76 35 12 99;

1.4 第三行:比較第 4 位和第 5 位的大小,發現 12 比 99 要小,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 18 76 35 99 12;?

遍歷第一次并經過 4 次排序后,5 個數中最小的一個?12 已經歸位到隊列的最后一位了(即第 5 位)。

2. 再看第二列:?

2.1 第一行:比較第 1 位和第 2 位的大小,發現 18 比 76 要小,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 76 18 35 99 12

2.2 第二行:比較第 2 位和第 3 位的大小,發現 18 比 35 要小,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 76 35 18 99 12

2.3 第三行:比較第 3 位和第 4 位的大小,發現 18 比 99 要小,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 76 35 99 18 12

遍歷第二次并經過 3 次排序后,5 個數中倒數第二小的一個?18 已經歸位到隊列的倒數第二位了(即第 4 位)。?

3. 再看第三列:?

2.1 第一行:比較第 1 位和第 2 位的大小,發現 76 比 35 要大,則不需要交換這兩個數的位置。并且這 5 個數的順序仍然是 76 35 99 18 12

2.2 第二行:比較第 2 位和第 3 位的大小,發現 35 比 99 要小,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 76 99 35 18 12

遍歷第三次并經過 2 次排序后,5 個數中倒數第三小的一個?35 已經歸位到隊列的倒數第三位了(即第 3 位)。??

3. 最后看第四列:?

2.1 第一行:比較第 1 位和第 2 位的大小,發現 76 比 99 要小,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 99 76 35 18 12

遍歷第四次并經過 1 次排序后,5 個數中倒數第四小的一個?76 已經歸位到隊列的倒數第四位了(即第 2 位)。?

最后總結一下:如果有 n 個數進行排序,只需將 n-1 個數歸位,也就是說要進行 n-1 次操作。而 “每一次” 都需要從第 1 位開始進行相鄰兩個數的比較,將較小的一個數放在后面,比較完畢后向后移一位繼續比較下面兩個相鄰數的大小,重復此步驟,直到最后一個尚未歸位的數,已經歸位的數則無需再進行比較。

冒泡降序例程1(推薦):?

#include <stdio.h>void main()
{int arr[5];int n;int tmp;scanf("%d", &n); //輸入一個數n,表示接下來有n個數for (int i = 0; i < n; i++) //循環讀入n個數到數組arr中scanf("%d", &arr[i]);//冒泡降序的核心代碼for (int i = 1; i <= n - 1; i++) { //n個數排序,只需進行 n-1 次(i從1開始,因此i需要包含 n-1)for (int j = 0; j < n - i; j++) { //i從1開始,則j從第1位(數組0下標)開始與后面一個數比較,直到最后一個尚未歸位的數(已歸位的數無需再比較,因此只需排序 n-i 次)if (arr[j] < arr[j+1]) { //相鄰兩個數比較大小并交換tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}}}//輸出結果for (int i = 0; i < n; i++)printf("%d ", arr[i]);printf("\n");
}

冒泡降序例程2:?

#include <stdio.h>void main()
{int arr[5];int n;int tmp;scanf("%d", &n); //輸入一個數n,表示接下來有n個數for (int i = 0; i < n; i++) //循環讀入n個數到數組arr中scanf("%d", &arr[i]);//冒泡降序的核心代碼for (int i = 0; i < n - 1; i++) { //n個數排序,只需進行 n-1 次(i從0開始,因此i不能包含 n-1)for (int j = 1; j < n - i; j++) { //i從0開始,則j從第2位(即數組1下標)開始與前面一個數比較,直到最后一個尚未歸位的數(已歸位的數無需再比較,因此只需排序 n-i 次)if (arr[j-1] < arr[j]) { //相鄰兩個數比較大小并交換tmp = arr[j-1];arr[j-1] = arr[j];arr[j] = tmp;}}}//輸出結果for (int i = 0; i < n; i++)printf("%d ", arr[i]);printf("\n");
}

冒泡降序例程3:??

#include <stdio.h>void main()
{int arr[5];int n;int tmp;scanf("%d", &n); //輸入一個數n,表示接下來有n個數for (int i = 0; i < n; i++) //循環讀入n個數到數組arr中scanf("%d", &arr[i]);//冒泡降序的核心代碼for (int i = 0; i < n - 1; i++) { //n個數排序,只需進行 n-1 次 (i從0開始,因此i不能包含 n-1)for (int j = 0; j < n - i - 1; j++) { //從第1位(數組0下標)開始與后面一個數比較,直到最后一個尚未歸位的數(已歸位的數無需再比較,然而i和j都是從0開始,因此只需排序 n-i-1 次)if (arr[j] < arr[j+1]) { //相鄰兩個數比較大小并交換tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}}}//輸出結果for (int i = 0; i < n; i++)printf("%d ", arr[i]);printf("\n");
}

2.2?冒泡升序(從小到大排序)

冒泡升序:每次比較相鄰的兩個數,如果后面的數比前面的數小,則交換這兩個數的位置。?

假設將 99 35 18 76 12 這 5 個數進行從小到大的排序(即,越大的越靠后)

如上圖所示,從左往右逐列看,5 個數總共需要遍歷 4 次(即 n - 1 次);而每列從上往下逐行看,每遍歷一次總共需要排序 n - i 次(i 代表遍歷的次數)。

1. 首先看第一列:?

1.1 第一行:比較第 1 位和第 2 位的大小,發現 99 比 35 要大,因為是升序,所以需要交換這兩個數的位置。交換之后這 5 個數的順序是 35 99 18 76 12;

1.2 第二行:比較第 2 位和第 3 位的大小,發現 99 比 18 要大,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 35 18 99 76 12;

1.3 第三行:比較第 3 位和第 4 位的大小,發現 99 比 76 要大,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 35 18 76 99 12;

1.4 第三行:比較第 4 位和第 5 位的大小,發現 99 比 12 要大,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 35 18 76 12 99

遍歷第一次并經過 4 次排序后,5 個數中最大的一個?99 已經歸位到隊列的最后一位了(即第 5 位)。

2. 再看第二列:?

2.1 第一行:比較第 1 位和第 2 位的大小,發現 35 比 18 要大,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 18 35 76 12 99

2.2 第二行:比較第 2 位和第 3 位的大小,發現 35 比 76 要小,則不需要交換這兩個數的位置。并且這 5 個數的順序仍然是 18 35 76 12 99

2.3 第三行:比較第 3 位和第 4 位的大小,發現 76 比 12 要大,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 18 35?12 76 99

遍歷第二次并經過 3 次排序后,5 個數中第二大的一個?76 已經歸位到隊列的倒數第二位了(即第 4 位)。?

3. 再看第三列:?

2.1 第一行:比較第 1 位和第 2 位的大小,發現 18 比 35 要小,則不需要交換這兩個數的位置。并且這 5 個數的順序仍然是 18 35?12 76 99

2.2 第二行:比較第 2 位和第 3 位的大小,發現 35 比 12 要大,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 18 12 35?76 99

遍歷第三次并經過 2 次排序后,5 個數中第三大的一個?35 已經歸位到隊列的倒數第三位了(即第 3 位)。??

3. 最后看第四列:?

2.1 第一行:比較第 1 位和第 2 位的大小,發現 18 比 12 要大,因此需要交換這兩個數的位置。交換之后這 5 個數的順序是 12 18 35?76 99

遍歷第四次并經過 1 次排序后,5 個數中第四大的一個?18 已經歸位到隊列的倒數第四位了(即第 2 位)。?

最后總結一下:如果有 n 個數進行排序,只需將 n-1 個數歸位,也就是說要進行 n-1 次操作。而 “每一次” 都需要從第 1 位開始進行相鄰兩個數的比較,將較大的一個數放在后面,比較完畢后向后移一位繼續比較下面兩個相鄰數的大小,重復此步驟,直到最后一個尚未歸位的數,已經歸位的數則無需再進行比較。

冒泡升序例程1(推薦):?

#include <stdio.h>void main()
{int arr[5];int n;int tmp;scanf("%d", &n); //輸入一個數n,表示接下來有n個數for (int i = 0; i < n; i++) //循環讀入n個數到數組arr中scanf("%d", &arr[i]);//冒泡降序的核心代碼for (int i = 1; i <= n - 1; i++)) { //n個數排序,只需進行 n-1 次(i從1開始,因此i需要包含 n-1)for (int j = 0; j < n - i; j++) { //i從1開始,則j從第1位(數組0下標)開始與后面一個數比較,直到最后一個尚未歸位的數(已歸位的數無需再比較,因此只需排序 n-i 次)if (arr[j] > arr[j+1]) { //相鄰兩個數比較大小并交換tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}}}//輸出結果for (int i = 0; i < n; i++)printf("%d ", arr[i]);printf("\n");
}

冒泡升序例程2:??

#include <stdio.h>void main()
{int arr[5];int n;int tmp;scanf("%d", &n); //輸入一個數n,表示接下來有n個數for (int i = 0; i < n; i++) //循環讀入n個數到數組arr中scanf("%d", &arr[i]);//冒泡降序的核心代碼for (int i = 0; i < n - 1; i++) { //n個數排序,只需進行 n-1 次(i從0開始,因此i不能包含 n-1)for (int j = 1; j < n - i; j++) { //i從0開始,則j從第2位(即數組1下標)開始與前面一個數比較,直到最后一個尚未歸位的數(已歸位的數無需再比較,因此只需排序 n-i 次)if (arr[j-1] > arr[j]) { //相鄰兩個數比較大小并交換tmp = arr[j-1];arr[j-1] = arr[j];arr[j] = tmp;}}}//輸出結果for (int i = 0; i < n; i++)printf("%d ", arr[i]);printf("\n");
}

冒泡升序例程3:?

#include <stdio.h>void main()
{int arr[5];int n;int tmp;scanf("%d", &n); //輸入一個數n,表示接下來有n個數for (int i = 0; i < n; i++) //循環讀入n個數到數組arr中scanf("%d", &arr[i]);//冒泡降序的核心代碼for (int i = 0; i < n - 1; i++) { //n個數排序,只需進行 n-1 次 (i從0開始,因此i不能包含 n-1)for (int j = 0; j < n - i - 1; j++) { //從第1位(數組0下標)開始與后面一個數比較,直到最后一個尚未歸位的數(已歸位的數無需再比較,然而i和j都是從0開始,因此只需排序 n-i-1 次)if (arr[j] > arr[j+1]) { //相鄰兩個數比較大小并交換tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}}}//輸出結果for (int i = 0; i < n; i++)printf("%d ", arr[i]);printf("\n");
}

三、冒泡排序應用?

假設一個班有 5 個學生,需要將這 5 個學生期末考試的分數,從高到低排序,并且輸出對應的學生姓名和性別。大家可以思考一下,該如何實現?

根據 2.1 冒泡降序原理,在此,我們只需要聲明一個結構體,其成員包含學生的姓名、性別和分數(假設滿分為 100,并分數只有整數)。下面是實際的例子。

#include <stdio.h>struct student {char name[24];char sex[8];int score;
};void main()
{struct student stu[5];struct student tmp;int n;scanf("%d", &n); //輸入班級總人數for (int i = 0; i < n; i++) //循環讀入學生總數到數組stu中scanf("%s %s %d", stu[i].name, stu[i].sex, &stu[i].score);//開始對學生進行分數排序for (int i = 1; i <= n - 1; i++) {for (int j = 0; j < n - i; j++) {if (stu[j].score < stu[j+1].score) { //比較相鄰的兩個數,分數高的排前面tmp = stu[j];stu[j] = stu[j+1];stu[j+1] = tmp;}}}//輸出結果for (int i = 0; i < n; i++)printf("%s %s %d", stu[i].name, stu[i].sex, &stu[i].score);printf("\n");
}

可以輸入以下數據進行驗證:

5

李文 男?80
韓飛 男?50
曉曉 女?86
胡峰 男?78
陳肖 女?66

運行結果是:?

曉曉 女?86

李文 男?80
胡峰 男?78
陳肖 女?66
韓飛 男?50

總結?

1.?冒泡降序:每次比較相鄰的兩個數,如果后面的數比前面數大,則交換這兩個數的位置;

2.?冒泡升序:每次比較相鄰的兩個數,如果后面的數比前面數小,則交換這兩個數的位置;

3. 從例程代碼來看,可知冒泡排序有很多種方法,但是萬變不離其宗,都是圍繞 “如果有 n 個數進行排序,則需遍歷?n-1 次,而?“每一次”?需要排序 n-i 次,并且都是從第 1 位開始進行相鄰兩個數的比較,將較小或較大的一個數放在后面,如此重復,直到最后一個尚未歸位的數” 展開。

4.?“冒泡降序” 與 “冒泡升序” 例程代碼的唯一差異是:相鄰的兩個數較小或較大的放在后面。例如,if (arr[j] <?arr[j+1]) 或?if (arr[j] > arr[j+1]);

5.?冒泡排序的核心部分是雙重嵌套循環。不難看出冒泡排序的時間復雜度是 O(N^{2})。這是一個非常高的時間復雜度。正如 Donald E. Knuth 所說:“冒泡排序除了它迷人的名字和導致了某些有趣的理論問題這一事實之外,似乎沒有什么值得推薦的。”

那還有沒有更好的排序算法呢?有,請看下章節——快速排序。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/214878.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/214878.shtml
英文地址,請注明出處:http://en.pswp.cn/news/214878.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux內存管理(十七):percpu 機制(2)——動態分配

源碼基于:Linux5.4 約定: 芯片架構:ARM64內存架構:UMACONFIG_ARM64_VA_BITS:39CONFIG_ARM64_PAGE_SHIFT:12CONFIG_PGTABLE_LEVELS :3關聯博文: percpu機制(1)——框架實現 percpu機制(2)——動態分配 0. 前言 上一篇博文 我們剖析了 percpu 機制的整個框架,包括per…

大致人類應該是短時記憶和利用短時記憶控制利用周圍環境達到長期記憶的吧

這里寫目錄標題 圖代碼代碼解析圖 代碼 import timedef route_llm(route_text):passdef write_to_dask(one_sum, one_text, one_path

小程序嵌套H5

小程序嵌套H5 使用Hbuild x開發H5頁面項目里面使用了js-sdk工具包H5發布完成之后生成URL。新建一個小程序空項目&#xff0c;填寫小程序的appid。本地調試的時候如果報錯無法打開該網頁&#xff0c;那么需要勾選先的不校驗。發布體驗版本需要注意下面的兩個配置點。 使用Hbuild…

中通快遞單號查詢入口,將指定某天簽收的單號篩選出來

批量查詢中通快遞單號的物流信息&#xff0c;將指定某天簽收的單號篩選出來。 所需工具&#xff1a; 一個【快遞批量查詢高手】軟件 中通快遞單號若干 操作步驟&#xff1a; 步驟1&#xff1a;運行【快遞批量查詢高手】軟件&#xff0c;并登錄 步驟2&#xff1a;點擊主界面左…

Spring Boot中JdbcTemplate多數據源配置

作者簡介&#xff1a;大家好&#xff0c;我是擼代碼的羊駝&#xff0c;前阿里巴巴架構師&#xff0c;現某互聯網公司CTO 聯系v&#xff1a;sulny_ann&#xff08;17362204968&#xff09;&#xff0c;加我進群&#xff0c;大家一起學習&#xff0c;一起進步&#xff0c;一起對抗…

編譯 Flink代碼

構建環境 JDK1.8以上和Maven 3.3.x可以構建Flink&#xff0c;但是不能正確地遮蓋某些依賴項。Maven 3.2.5會正確創建庫。所以這里使用為了減少問題選擇 Maven3.2.5版本進行構建。要構建單元測試&#xff0c;請使用Java 8以上&#xff0c;以防止使用PowerMock運行器的單元測試失…

云計算核心技術

1.1 云計算的定義 云計算是目前業內的熱點概念&#xff0c;它以開放的標準和服務為基礎&#xff0c;以互聯網為中心&#xff0c;提供安全、快速、便捷的數據存儲和網絡計算服務&#xff0c;讓互聯網這片“云”上的各種計算機共同組成數個龐大的數據中心及計算中心。它可以被看成…

求職智能分析系統

本項目是一個基于Flask輕量級框架的計算機就業數據可視化分析平臺。 采用echarts和ajax等技術進行數據展示和用戶交互。

【電路筆記】-電位器

電位器 文章目錄 電位器1、概述2、電位器類型2.1 旋轉電位器2.2 滑塊電位器2.3 預設和微調電位器2.4 變阻器 3、電位器示例14、電位器作為分壓器5、電位器示例26、變阻器6、滑塊變阻器7、線性或對數電位器8、總結 當連接的軸物理旋轉時&#xff0c;電位計和變阻器的電阻值會發生…

一個簡單的Wireshark和TCP三次握手,為什么能難住阿里6年測試?

之前寫過一篇博客&#xff1a;用 Fiddler 來調試HTTP&#xff0c;HTTPS。 這篇文章介紹另一個好用的抓包工具wireshark&#xff0c; 用來獲取網絡數據封包&#xff0c;包括http,TCP,UDP&#xff0c;等網絡協議包。 記得大學的時候就學習過TCP的三次握手協議&#xff0c;那時候…

Vue中 v-show 和 v-if 有什么區別

Vue中的 v-show 和 v-if 一.v-show 與 v-if 原理分析v-show 原理v-if 原理 二、v-show 與 v-if 的共同點三、v-show 與 v-if 的區別四、v-show 與 v-if 的使用場景使用 v-show 的場景&#xff1a;使用 v-if 的場景&#xff1a; 五、v-show 與 v-if 的優缺點v-show優點&#xff…

kafka rebalance(再均衡)導致的消息積壓分析

起因&#xff1a; 某天&#xff0c;項目組收到大量的kafka消息積壓告警。查看了kafka日志后&#xff0c;發現 kafka不斷地 rebalance(再均衡)。 Rebalance (再均衡)&#xff1a; 分區的所有權從一個消費者轉移到另一個消費者&#xff0c;這樣的行為被稱為Rebalance (再均衡)…

修改汽車的控制系統實現自動駕駛,基于一個開源的汽車駕駛輔助系統實現全自動駕駛

修改汽車的控制系統實現自動駕駛,基于一個開源的汽車駕駛輔助系統實現全自動駕駛。 自動駕駛汽車依靠人工智能、視覺計算、雷達、監控裝置和全球定位系統協同合作,讓電腦可以在沒有任何人類主動的操作下,自動安全地操作機動車輛。 演示視頻: Openpilot :一個開源的汽車駕…

Socks5代理與代理IP的技術創新

隨著全球市場的開放和跨界電商的崛起&#xff0c;企業在出海過程中面臨著復雜多變的網絡環境和地域限制。在這一背景下&#xff0c;Socks5代理和代理IP等技術應運而生&#xff0c;成為助力企業突破網絡壁壘、實現出海目標的重要工具。本文將深入探討Socks5代理和代理IP在跨界電…

OpenSSL 3.x爆出漏洞,如何妥善應對?

10月25日&#xff0c;OpenSSL項目團隊發布了OpenSSL 3.x版中一個關鍵安全漏洞的修復程序。該修復程序已于11月1日正式發布。 由于OpenSSL有著極為廣泛的使用&#xff0c;該公告引起了很大反響。Akamai希望能通過本文幫助相關用戶了解情況&#xff0c;介紹有關檢測和緩解威脅的…

怎么消除視頻中所有的聲音?方法很簡單

當我們想把視頻中去掉聲音&#xff0c;可能有多種原因&#xff0c;也許需要制作一個無聲視頻&#xff0c;或者想在視頻中添加自己的音樂或解說&#xff0c;特別是一些搞笑解說&#xff0c;無論原因是什么&#xff0c;到底要怎么把視頻中所有的聲音都去除呢&#xff1f; 小編給…

計算機畢業設計 基于Web的網上購物系統(pc端仿淘寶系統)的設計與實現 Java實戰項目 附源碼+文檔+視頻講解

博主介紹&#xff1a;?從事軟件開發10年之余&#xff0c;專注于Java技術領域、Python人工智能及數據挖掘、小程序項目開發和Android項目開發等。CSDN、掘金、華為云、InfoQ、阿里云等平臺優質作者? &#x1f345;文末獲取源碼聯系&#x1f345; &#x1f447;&#x1f3fb; 精…

SVN優缺點詳解及版本控制系統選型建議

Subversion (SVN)是目前可用的眾多版本控制選項之一。本篇文章將全面概述什么是 SVN、SVN的歷史、SVN存儲庫是什么&#xff0c;以及在切換到SVN之前您應該謹慎考慮的潛在問題。 什么是Subversion&#xff08;SVN&#xff09;&#xff1f; Subversion軟件&#xff0c;也稱為SV…

管理類聯考——數學——真題篇——按知識分類——代數

文章目錄 2023真題(2023-09)-代數-一元二次方程-注意絕對值的有效性真題(2023-17)-代數-一元二次方程-舉反例真題(2023-18)-數列-等比數列真題(2023-24)-數列-等比數列2022真題(2022-03)-代數-整式-因式分解真題(2022-19)-數列-等比數列真題(2022-21)-數列-等比數…

Docker的常用命令(沒有廢話)

目錄 鏡像 鏡像管理命令 鏡像構建命令 鏡像標簽和推送命令 其他命令 容器 運行容器 停止和刪除容器 查看容器信息 進入容器 數據卷 列出卷 創建和刪除卷 將卷掛載到容器 鏡像 鏡像管理命令 docker images # 列出本地所有的鏡像 docker search <關鍵詞> #…