[數據結構] 基于交換的排序 冒泡排序快速排序

標題:[數據結構] 基于交換的排序 冒泡排序&&快速排序

@水墨不寫bug


(圖片來源于網絡)?


目錄

(一)冒泡排序

優化后實現:

(二)快速排序

I、實現方法:?

(1)hoare法

hoare法實現快排:

?(2)挖坑法

挖坑法實現:

(3)雙指針法?

雙指針法實現:?

?II、快速排序復雜度分析:

比較完備的快速排序實現如下:


正文開始:

(一)冒泡排序

?

時間復雜度:O(N^2)

空間復雜度:O(1)

特點:數組接近有序時,可通過優化來提高效率。

穩定性:穩定

冒泡排序:

? ? ? ? 基本思想:大數下沉,小數上浮。

? ? ? ? 實現思路:從內循環到外循環,從一趟到多趟。

????????冒泡排序通過兩層循環來實現,內層循環實現其中的一趟遍歷,在一趟的遍歷中,需要注意要控制好左右區間邊界,冒泡排序的實現方式是多樣的,無論用何種實現方式,最主要的是控制好邊界,以及內外層循環的銜接;以下是一種冒泡排序的寫法:


void BubbleSort(vector<int>& nums)
{int n = nums.size();for (int j = 0; j < n - 1; ++j){for (int i = 0; i < n - 1 - j; ++i){if (nums[i] > nums[i + 1]){::swap(nums[i], nums[i + 1]);}}}
}

優化:

? ? ? ? 如果在一次遍歷的過程中,沒有進入if()交換,這已經說明數組已經有序,可以直接停止排序。

優化后實現:


void BubbleSort(vector<int>& nums)
{int n = nums.size();for (int j = 0; j < n - 1; ++j){int ex = 0;for (int i = 0; i < n - 1 - j; ++i){if (nums[i] > nums[i + 1]){ex = 1;::swap(nums[i], nums[i + 1]);}}if (ex == 0)break;}
}


(二)快速排序

時間復雜度:O(NlogN)

空間復雜度:

特點:當數據接近有序,比如逆序的時候;或者選取的key在數據中大量存在時,快速排序時間復雜度會退化為O(N^2),這是相當嚴重的缺陷。

穩定性:不穩定。

????????快速排序是Hoare于1962年提出的一種二叉樹結構的交換排序方法。

????????基本思想:任取待排序元素序列中的某元素(記為key)作為基準值,按照key值將待排序集合分割成兩子序列,左子序列中所有元素均小于基準值key,右子序列中所有元素均大于基準值key。然后遞歸,左右子序列重復該過程,直到所有元素都排列在相應位置上為止。

? ? ? ? 本質就是將數組根據key值分為兩部分,一部分比key大,一部分比key小。對于每一個部分,再次進行如上操作,直到數組不可再分為止。這就是遞歸實現的淺層次的直觀理解。但是遞歸不是本文的重點,關于遞歸,我會在后面與你分享。?

I、實現方法:?

(1)hoare法

? ? ? ? hoare法是快排的提出者hoare提供的方法,是一種經典的實現方法。

實現原理:

? ? ? ? 定義兩個下標:左下標L? 和? 右下標R;

? ? ? ? 隨機選取一個key值,習慣上我們選擇區間的最左側的元素為key;

? ? ? ? 讓右下標先走,向左尋找比key小的值,找到后停下來:

?停下來后:

?左下標再向右尋找比key大的值,找到后停下來:

此時,交換兩個下標對應的值:

?

接下來繼續執行上述步驟(R先走),我展示關鍵步驟:

?兩下標找到要求目標并交換:

直到遇到特殊情況:兩下標相遇

?

?這時停止停止循環,將最左側元素與相遇處的元素交換位置:
即可完成一次二分。

????????接下來,對于左右區間再次進行上述操作,直到區間不可再分為止。


但是如何保證相遇處的值一定小于key呢?

對于相遇這個事件,有且僅有兩種情況:

只可能是R向左移動遇到L;或者是L向右移動遇到R;

????????(1)R向左移動遇到L:有兩種可能情況

? ? ? ? ? ? ? ? ? ? ? ? a,第一次R由于沒有找到比key小的值,直接一路向左遇到left,此時left就是key,然后執行自己與自己交換:此時相遇的位置的值就是key本身。

? ? ? ? ? ? ? ? ? ? ? ? b,第一次之后R向左遇到L,你要想清楚,在此之前L停止的地方是被交換后的原先R的值(它是比key小的);在這樣的前提條件下,R向左移動與L相遇了,說明R沒有找到小于key的元素,與L相遇后指向L的比key小的值。

? ? ? ? (2)L向右移動遇到R

? ? ? ? ? ? ? ? ? ? ? ? R先走,在找到比key小的位置停下,在此前提下,L向右移動與R相遇了,L指向R的比key小的值。

hoare法實現快排:


void QuickSort(vector<int>& nums,int left,int right)
{//遞歸出口,此時區間不存在或者只有一個值if (left >= right)return;//保存左右下標的值,便于在遞歸時找到原來的區間邊界int begin = left, end = right;//keyi來記錄左區間的下標int keyi = left;while (left < right){//右下標先走,找小while (left < right && nums[keyi] <= nums[right]){--right;}//左區間再走,找大while (left < right && nums[left] <= nums[keyi]){++left;}::swap(nums[left], nums[right]);}//此時一趟完畢,將key與相遇位置交換::swap(nums[left], nums[keyi]);keyi = left;//更新keyi//遞歸左右區間QuickSort(nums, begin, keyi);QuickSort(nums, keyi+1, end);
}

?(2)挖坑法

實現原理:

? ? ? ? 由于左邊有坑,所以右下標先走。

? ? ? ? 找小,找到后停下來,將找到的值放在坑中,R的位置就成為了新的坑:

此時坑在右邊,左邊下標先走,找大:

找到后交換,左邊又成為新的坑。

以此類推,直到左右相遇,相遇的位置一定是坑,此時將key放到坑中,完成單趟:

依然是左邊都是比6小,右邊都是比6大,說明沒有錯誤。

挖坑法實現:

void QuickSort_(vector<int>& nums, int left, int right)
{if (left >= right)return;int begin = left, end = right;int key = nums[left];//記住key的值int hole = left;//開始挖坑while (left < right){//右先找比key大的while (left < right && nums[right] >= key)right--;//找到后,填坑,然后挖新坑nums[hole] = nums[right];hole = right;//左找比key小的while (left < right && nums[left] <= key)left++;//找到后,填坑,然后挖新坑nums[hole] = nums[left];hole = left;}//此時相遇了,把key值放在坑里nums[hole] = key;QuickSort_(nums,begin,hole);QuickSort_(nums,hole + 1,end);
}

(3)雙指針法?

?

// 設置前指針prev,指向首元素,遍歷指針cur指向第二個元素,
// 接下來cur開始找小,如果沒找到小,就一直往前走;

//如果找到小的了,就先停下來,然后prev往前走一步,再和cur交換值,然后cur繼續向后,重復上述步驟,
// 最后cur走出數組后,循環終止!此時prev指向的位置和keyi的位置交換。

我們詳細看一下過程:

????????

雙指針法實現:?


void QuickSort__(vector<int>& nums, int left, int right)
{if (left >= right)return;int begin = left, end = right;int prev = left;int cur = left + 1;int keyi = left;while (cur <= right)//cur走出數組循環停止{//cur一直在走,如果遇到比keyi小的,就停下來等perv走一步后交換,再接著走if (nums[cur] < nums[keyi] && ++prev != cur)swap(nums[prev], nums[cur]);cur++;}//cur出去后,prev的值和keyi交換swap(nums[keyi], nums[prev]);QuickSort__(nums,left,keyi);QuickSort__(nums,keyi+1,end);}

?II、快速排序復雜度分析:

? ? ? ? 傳統的快速排序在處理一些極端問題時會顯得無力,接下來我們就來討論這些極端情況,并且給出應對極端情況的方法:

1.對于選擇key不合適的問題:

? ? ? ? 在數組元素接近逆序的時候,由于我們總是在區間的最左側選取key,如果數組接近逆序,這時選取的key無法有效的將數組分為兩個等大的數組,這就導致一次只能排序一個元素,這導致快速排序的復雜度會退化為O(N^2),這就需要我們不能隨便取key。可以通過隨機數法在區間內隨機取一個元素作為key即可。

2.關于選擇key大量出現的問題:

? ? ? ? 如果key大量出現,也會導致上述的情況,一次只能排序一個數,所以我們不能隨便分區間,這就要求我們將數組分為三部分,左側區間都小于key,中間區間則是數值等于key的元素,右側區間是大于key的數值。

比較完備的快速排序實現如下:

class Solution {
public:vector<int> sortArray(vector<int>& nums) {srand(time(NULL));qsort(nums,0,nums.size()-1);return nums;}void qsort(vector<int>& nums,int l,int r){//遞歸出口if(l >= r) return;//數組分三塊int key = GetRandom(nums,l,r);int cur = l,left = l-1,right = r+1;while(cur < right){if(nums[cur] < key) swap(nums[++left],nums[cur++]);else if(nums[cur] == key) cur++;else swap(nums[--right],nums[cur]); }//遞歸排序子區間qsort(nums,l,left);qsort(nums,right,r);}int GetRandom(vector<int>& nums,int left,int right){return nums[ rand() % ( right - left + 1 ) + left];}
};

?完~

未經作者同意禁止轉載

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

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

相關文章

opencv環境搭建-python

最近遇到了一些圖像處理的需求&#xff0c;所以需要學習一下opencv,來記錄一下我的學習歷程。 安裝numpy pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy安裝matplotlib pip install -i https://pypi.tuna.tsinghua.edu.cn/simple matplotlib安裝opencv …

ctfshow web入門 web338--web344

web338 原型鏈污染 comman.js module.exports {copy:copy };function copy(object1, object2){for (let key in object2) {if (key in object2 && key in object1) {copy(object1[key], object2[key])} else {object1[key] object2[key]}}}login.js var express …

【ubuntu】掛載新磁盤

1、查看磁盤 sudo fdisk -l#Disk /dev/sdb: 4.0 TiB #Disk model: HNA641010BCF105 #Units: sectors of 1 * 512 512 bytes #Sector size (logical/physical): 512 bytes / 4096 bytes #I/O size (minimum/optimal): 4096 bytes / 4096 bytes #Disklabel type: gpt #Disk id…

python argparse模塊nargs用法

nargs 是 argparse 模塊中用來指定參數的數量的屬性。不同的 nargs 取值有不同的含義&#xff0c;下面是一些常用的用法&#xff1a; nargsNone (默認值)&#xff1a;表示該參數只能接收一個值。例如&#xff1a;--foo 123。 nargs?&#xff1a;表示該參數最多接收一個值。如…

gcc/g++的四步編譯

目錄 前言1.預處理&#xff08;進行宏替換&#xff09;2.編譯&#xff08;生成匯編&#xff09;3.匯編&#xff08;生成二進制文件&#xff09;4. 鏈接 &#xff08;生成可執行文件&#xff09;a. 動態庫 && 動態鏈接b. 靜態庫 && 靜態鏈接c. 驗證d. 動靜態鏈接…

技術實現路徑怎么寫?(Word項目技術路徑文檔參考)

軟件項目編寫技術實現路徑至關重要&#xff0c;因為它為項目團隊提供了清晰的開發藍圖。這一路徑明確了從項目啟動到交付各階段所需的技術方案、步驟及預期成果&#xff0c;有助于團隊統一認識&#xff0c;確保開發工作有序進行。同時&#xff0c;技術實現路徑有助于識別潛在的…

HetuEngine簡介

目錄 HetuEngine是什么&#xff1f; HetuEngine的特點以及使用場景 特點 使用場景 HetuEngine介紹 結構 近期用到了Hetu&#xff0c;了解下這個工具是起什么作用的。 HetuEngine是什么&#xff1f; 是引擎&#xff0c;設計是為了讓與當前的大數據生態完美融合的引擎&am…

本安防爆手機:危險環境下的安全通信解決方案

在石油化工、煤礦、天然氣等危險環境中&#xff0c;通信安全是保障工作人員生命安全和生產順利進行的關鍵。防爆智能手機作為專為這些環境設計的通信工具&#xff0c;提供了全方位的安全通信解決方案。 防爆設計與材料&#xff1a; 防爆智能手機采用特殊的防爆結構和材料&…

Mysql部署MHA高可用

部署前準備&#xff1a; mysql-8.0.27下載地址&#xff1a;https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.27-1.el7.x86_64.rpm-bundle.tar mha-manager下載地址&#xff1a;https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-mana…

【Selenium】 使用save_screenshot截圖無法保存圖片

Selenium 使用save_screenshot截圖無法保存 代碼如下 from time import sleep from selenium import webdriver driver webdriver.Chrome() driver.maximize_window() driver.get(http://www.baidu.com) # 截取當前窗口&#xff0c;指定截圖圖片的保存位置 driver.save_scre…

為什么需要做網絡安全服務?

網絡安全服務之所以重要&#xff0c;是因為它在保護數字資產、維護企業運營、確保法規遵從、防范惡意行為以及建立信任等方面扮演著關鍵角色。以下是一些主要的理由&#xff1a; 保護核心資產和數據&#xff1a; 數字化轉型使得企業數據變得極其寶貴&#xff0c;包括知識產權、…

深度學習模型加密python版本

支持加密的模型: # torch、torch script、onnx、tensorrt 、torch2trt、tensorflow、tensorflow2tensorrt、paddlepaddle、paddle2tensorrt 深度學習推理模型通常以文件的形式進行保存&#xff0c;相應的推理引擎通過讀取模型文件并反序列化即可進行推理過程. 這樣一來&#…

數據庫——事務管理

title: 數據庫——事務管理 date: 2024-07-06 11:55:39 tags: 數據庫 categories: 數據庫 cover: /image/T1.jpg description: 數據庫的事務管理的相關知識 事務管理 事務管理是對一系列數據庫操作進行管理的過程&#xff0c;這些操作被視為一個不可分割的工作單元&#xff0…

20K Stars!一個輕量級的 JS 庫

大家好,我是CodeQi! 一位熱衷于技術分享的碼仔。 Driver.js 是一個輕量級的 JavaScript 庫,旨在幫助開發人員創建網站或應用程序的引導和教程。通過 Driver.js,您可以引導用戶了解網站的各個功能和使用方式。 Driver.js 提供了高度可定制的功能,使其能夠適應各種需求和…

寶塔-Linux模板常用命令-centos7

一、寶塔-Linux模板常用命令&#xff1a; 1.停止寶塔 /etc/init.d/bt stop 2.啟動寶塔 /etc/init.d/bt start 3.重啟寶塔 /etc/init.d/bt restart 4.卸載寶塔 /etc/init.d/bt stop && chkconfig --del bt && rm -f /etc/init.d/bt && rm -rf …

如何使用echart做K線圖

使用ECharts制作K線圖需要先引入ECharts的庫文件&#xff0c;然后通過調用相應的API來配置和渲染K線圖。以下是一個簡單的示例代碼&#xff1a; // 引入ECharts庫文件 <script src"https://cdn.jsdelivr.net/npm/echarts5.0.0/dist/echarts.min.js"></scri…

使用Python繪制和弦圖

使用Python繪制和弦圖 和弦圖效果代碼 和弦圖 和弦圖用于展示數據的多對多關系&#xff0c;適合用于社交網絡、交通流量等領域的分析。 效果 代碼 import pandas as pd import holoviews as hv from holoviews import opts hv.extension(bokeh)# 示例數據 data [(A, B, 2),…

想在vue中預覽doxc,excel,pdf文件? vue-office提供包支持

在浩瀚的Vue生態中&#xff0c;vue-office猶如一顆璀璨的星辰&#xff0c;以其獨特的魅力照亮了開發者處理多種文件格式的預覽之路。這款精心打造的Vue組件庫&#xff0c;不僅擁抱了Vue2的經典&#xff0c;也緊密跟隨Vue3的步伐&#xff0c;展現了卓越的技術前瞻性和兼容性。它…

印尼網絡安全治理能力觀察

在全國國際機場的移民服務完全癱瘓 100 多個小時后&#xff0c;印尼政府承認其新成立的國家數據中心 (PDN) 遭受了網絡攻擊。 惡意 Lockbit 3.0 勒索軟件加密了存儲在中心的重要數據&#xff0c;其背后的黑客組織要求支付 800 萬美元的贖金。 不幸的是&#xff0c;大多數數據…

遞推平均濾波法(又稱滑動平均濾波法)

遞推平均濾波法(又稱滑動平均濾波法) 遞推平均濾波法:把連續取得的N個采樣值看成一個隊列,隊列的長度固定為N,每次采樣到一個新數據放入隊尾,并扔掉原來隊首的一次數據(先進先出原則),把隊列中的N個數據進行算術平均運算,獲得新的濾波結果。 優點: 對周期性干擾有良…