常規算法學習

算法

  • 1. 排序算法
    • 1. 歸并排序
      • 1.1 普通歸并排序
      • 1.2 優化后的歸并排序(TimSort)
    • 2. 插入排序
      • 2.1 直接插入排序
      • 2.2 二分插入排序
      • 2.3 成對插入排序
    • 3. 快速排序
      • 3.1 單軸快速排序
      • 3.2 雙軸快排
    • 4. 計數排序
  • 2. 樹
    • 1. 紅黑樹(Red Black Tree)
      • 1.1 紅黑樹的定義或者是約束條件
      • 1.2 紅黑樹添加節點:
      • 1.3 紅黑樹刪除節點

1. 排序算法

1. 歸并排序

1.1 普通歸并排序

歸并排序比較適用于處理較大規模的數據,且比較消耗內存。所以小規模的序列,一般不使用歸并排序。

基本思想:

? 就是“分治”思想,先將序列元素拆解,然后歸并,即合并相鄰有序子序列。

在這里插入圖片描述

1.2 優化后的歸并排序(TimSort)

自適應、穩定、高效的排序算法,源自合并排序和插入排序。

我們來進行歸并排序的時候,就進行了許多沒必要的“分”,因為有些子序列本來就是有序的了,隨而也導致沒必要的“治”。TimSort就是為了解決這一缺陷而生。

Timsort的思想是,“分”的時候,直接從左往右,劃分成各種不同長度的、有序的子序列(每個子序列叫做一個run,),然后對這些子序列進行歸并,這樣一來,復雜度就大大降低了。

有序的子序列(Run):遞增的序列或者是嚴格遞減的序列(保證算法的穩定性,遞減的序列需要進行翻轉)。

minRun:最小的有序子序列的長度。如果有一個run的長度沒有達到minrun,那就要從run序列后面的元素進行二分插入放入到run中,直到run的長度達到最小minrun。

minrun的選擇:16-64之間,數組的長度/minrun 略小于等于2的次冪。

子序列合并:

? 需要使用棧。從第一個run開始依次入棧,每入棧一次,就要檢查:

在這里插入圖片描述

直到棧中所有run都滿足上述要求,繼續將下一個run放入到棧中。最終合并成一個。(為什么上圖這么合并:如果違反了下面的兩條規則,則Y與X、Z中的較小者合并。規則使得合并保持近似平衡,同時在延遲合并以實現平衡)

2. 插入排序

2.1 直接插入排序

基本思想:序列分為兩部分,一部分有序,一部分無序,不斷從無序的部分選元素出來,插入到有序的部分。(一開始是認為第一個元素是有序的部分,其他元素都是無序的部分)

插入排序一般應用于數據量較小的序列排序中。因為插入排序在小數組中已經表現的很好了。

2.2 二分插入排序

與直接插入排序不同點是:直接插入排序是待插入的元素依次和前一個元素進行比較、交換,直到滿意位為止;二分插入排序是先從有序數組中通過二分查找確定待插入的位置,然后將后面的元素依次后移一位,并將帶插入元素插入其中。減少了比較次數。

2.3 成對插入排序

在直接插入排序里面,我們在進行插入的時候,需要在每次循環時,不斷與有序的元素進行比較,直到找到合適位置。而比較次數與移位次數是衡量一個算法優劣的標準。

成對插入排序是為了減少比較次數而生。

  • 基本思想:
    第一步:在無序部分拿兩個元素a1,a2,并調整使a1>a2;
    第二步:a1往左比較,找到合適位置后插入;
    第三步:a2只需在a1的左邊進行比較(a1>a2),找到合適的位置插入即可。

3. 快速排序

3.1 單軸快速排序

基本思想
第一步:選其中一個元素出來作為軸。
第二步:兩邊同時開始遍歷,比軸小的元素放在左邊,比軸大的元素放在右邊。
第三步:對上面被軸分開的兩個序列,進行遞歸處理,重復執行一二步。最終得到一個有序序列

3.2 雙軸快排

單軸很多時候可能會遇到較差的情況就是選取的元素可能是最大的或者最小的元素,這樣元素就沒辦法將元素進行劃分,時間復雜度也就變成了 T ( n ) = T ( n ? 1 ) + O ( n ) , T ( n ) = O ( n 2 ) T(n) = T(n-1)+O(n), \quad T(n) = O(n^2) T(n)=T(n?1)+O(n),T(n)=O(n2)?。

雙軸快排,顧名思義,就是按兩個軸,分成三個區。對于單軸快排,選取的軸是最大的或者最小的元素就會導致排序性能降低。對于雙軸快排,只有兩個軸一個選取最大,一個選取最小,才會使性能降低,這種概率比快排的概率小太多了。所以,雙軸快排的優化力度還是挺大的。

選取待排序的最左側、最右側的兩個數作為軸pivot1、pivot2,并且保證pivot1< pivot2,不滿足就交換。通過交換數組中的元素,小于pivot1的元素放在pivot1左側,大于pivot2的元素放在最右側,在兩者之間的放在中間。

在這里插入圖片描述
然后,依次遞歸下去。

交換過程:

start和end一直不動,直到排好在進行交換。
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

4. 計數排序

計數排序適用于元素個數遠大于元素種數的情況,適用于Short、Byte、Char等元素種數較少的類型。

基本思想:
①:先創建一個length為元素種數的數組count,里面的元素全部為0。
②:遍歷要排序的序列,根據序列元素大小a找到數組count的位置,對count[a]+=1;
(舉個例子:若剛好遍歷到的元素是55,則找到count[55]+=1)
③:從左到右遍歷count[],元素不是0的位置都拿出來,根據count[a]拿多少個。
④:最終得到有效序列。

2. 樹

1. 紅黑樹(Red Black Tree)

1.1 紅黑樹的定義或者是約束條件

  1. 節點要么是紅色要么是黑色
  2. 根節點必須是黑色
  3. 葉子節點掛兩個空節點(邏輯上)是黑色
  4. 每個紅色節點有兩個黑色子節點,推導出一條路徑上不能有兩個連續的紅色節點
  5. 每條路徑上必須有相同數量的黑色節點

1.2 紅黑樹添加節點:

待插入節點是紅色的,然后按照二叉搜索將待插入節點插入到葉子結點。

父節點叔節點紅色黑色
紅色變色(父節點、叔節點變黑,祖節點變紅。然后把祖節點當做新插入的節點遞歸上述操作)無需操作
黑色旋轉(旋轉完成之后,再根據變色原則,進行變色,這個過程中同樣也會遇到旋轉,但你已經明白了旋轉的規律了。)無需操作

四種旋轉情況(根據剛插入節點、父節點、祖節點的位置):

在這里插入圖片描述
在這里插入圖片描述

1.3 紅黑樹刪除節點

首先看一下二叉搜索樹刪除節點操作

先說一下如何刪除二叉樹查找樹的節點吧。總共有三種情況

1.被刪除的節點是葉子節點,這時候只要把這個節點刪除,再把指向這個節點的父節點指針置為空就行

2.被刪除的節點有左子樹,或者有右子樹,而且只有其中一個,那么只要把當前刪除節點的父節點指向被刪除節點的左子樹或者右子樹就行

3.被刪除的節點既有左子樹而且又有右子樹,這時候需要把左子樹的最右邊的節點或者右子樹最左邊的節點提到被刪除節點的位置

紅黑樹中刪除一個節點,遇到的各種情形就是其子節點的狀態和顏色的組合,子節點狀態共有3種:無子節點、有一個子節點、有兩個子節點,顏色有紅色和黑色兩種,所以共會有6種組合。

  1. 紅黑樹刪除節點也要滿足二叉搜索樹的左小右大。因此,刪除兩個節點的情況和二叉搜索樹的情況一樣,轉換成刪除0個或者1個節點的情況。
  2. 只有一個子節點的情況,該節點不能是紅色,只能是黑色。

可能出現的組合:

組合1:被刪節點無子節點,且被刪結點為紅色

這是最簡單的一種情況,直接將節點刪除即可,不破壞任何紅黑樹的性質

組合2:被刪結點無子結點,且被刪結點為黑色

這是最復雜的情況,我們稍后再討論

組合3:被刪結點有一個子結點,且被刪結點為黑色
在這里插入圖片描述

這種組合下,被刪結點node的另一個子結點value必然為紅色,此時直接將node刪掉,用value代替node的位置,并將value著黑即可。

再論組合2:被刪結點無子結點,且被刪結點為黑色

因為刪除黑色結點會破壞紅黑樹的性質5,所以為了不破壞性質5,將node刪除后用一個擁有額外黑色的null替代它(可以想象是將node刪除后,在這個位置放了一個黑色的權值),剩下的就是調平的過程,最終這個游離的黑色權值被扔掉,整個刪除操作完成。

在這里插入圖片描述

然后再結合node的父結點father和其兄弟結點brother來分析。

情形一:brother為黑色,且brother有一個與其方向一致的紅色子結點son

所謂方向一致,是指brother為father的左子結點,son也為brother的左子結點;或者brother為father的右子結點,son也為brother的右子結點。

在這里插入圖片描述

情形二:brother為黑色,且brother有一個與其方向不一致的紅色子結點son

在這里插入圖片描述

轉換成情形1,接著操作。

情形三:brother為黑色,且brother無紅色子結點

此時若father為紅,則重新著色即可,刪除操作完成。

在這里插入圖片描述

此時若father為黑,則重新著色,將游離的黑色權值存到father(此時father的黑色權重為2),將father作為新的結點進行情形判斷,遇到情形一、情形二,則進行相應的調整,完成刪除操作;如果沒有,則結點一直上溯,直到根結點存儲額外的黑色,此時將該額外的黑色扔掉,即完成了刪除操作。(這個情景是最難的,好好理解)
在這里插入圖片描述

情形四:brother為紅色,則father必為黑色。

在這里插入圖片描述

圖(i)中,將brother和father旋轉,重新上色后,變成了圖(j),新的brother(原來的son)變成了黑色,這樣就成了情形一、二、三中的一種。
圖(i)中的情形顛倒過來,也是一樣的操作。

總而言之,基本操作原則就是:一個黑色節點被刪除之后,那么它的兄弟分支的節點分配給它一個或者是兄弟分支也減少一個,父節點從紅色變黑色。

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

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

相關文章

關于線程死鎖的相關知識

前言 今天學習了線程死鎖的相關知識。線程死鎖是非常重要的知識&#xff0c;寫成博客&#xff0c;加深自己對于知識的理解。 線程死鎖 結語 希望可以幫助到大家~

EMQX啟用單向認證的SSl/TLS連接的配置步驟

先確保您已經安裝了 OpenSSL 執行openssl version -a 獲取 openssl.cnf 目錄 生成自簽名服務端證書 CA 證書生成 server-ca.crt openssl req \-new \-newkey rsa:2048 \-days 365 \-nodes \-x509 \-subj "/CCN/OEMQ Technologies Co., Ltd/CNEMQ CA" \-keyout s…

依賴nacos實例動態創建線程池并監聽服務上下線

版本 Spring Booot 版本 3.2.4Spring Cloud 版本 2023.0.1Spring Cloud Alibaba 版本 2023.0.1.2 依賴 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </depe…

全面指南:使用Node.js和Python連接與操作MongoDB

在現代Web開發中&#xff0c;數據庫是存儲和管理數據的核心組件。MongoDB作為一款流行的NoSQL數據庫&#xff0c;以其靈活的數據模型、高性能和易擴展性廣受開發者歡迎。無論是使用Node.js還是Python&#xff0c;MongoDB都提供了強大的官方驅動和第三方庫&#xff0c;使得數據庫…

LeetCode 3068.最大節點價值之和:腦筋急轉彎+動態規劃(O(1)空間)

【LetMeFly】3068.最大節點價值之和&#xff1a;腦筋急轉彎動態規劃&#xff08;O(1)空間&#xff09; 力扣題目鏈接&#xff1a;https://leetcode.cn/problems/find-the-maximum-sum-of-node-values/ 給你一棵 n 個節點的 無向 樹&#xff0c;節點從 0 到 n - 1 編號。樹以長…

HTTPS加密通信詳解及在Spring Boot中的實現

HTTPS&#xff08;Hyper Text Transfer Protocol Secure&#xff09;是HTTP的安全版本&#xff0c;通過SSL/TLS協議為通訊提供加密、身份驗證和數據完整性保護。 一、HTTPS核心原理 1.加密流程概述 客戶端發起HTTPS請求&#xff08;連接到服務器443端口&#xff09;服務器返…

解決線程安全問題

前言 昨天學習了如何去解決線程不安全的問題。一般方法都是通過加鎖來處理&#xff0c;跟大家分享一波 。 解決線程安全問題 結語 希望可以幫助到大家~ byebye

網絡常識:網線和光纖的區別

網絡常識&#xff1a;網線和光纖的區別 一. 介紹二. 網線2.1 什么是網線&#xff1f;2.2 網線的主要類別2.3 網線的優勢2.4 網線的劣勢 三. 光纖3.1 什么是光纖&#xff1f;3.2 光纖的主要類別3.3 光纖的優勢3.4 光纖的劣勢 四. 網線 vs 光纖&#xff1a;誰更適合你&#xff1f…

win11 禁用/恢復 內置筆記本鍵盤(保證管用)

文章目錄 禁用啟用 禁用 1&#xff09;按下 win x&#xff0c;點擊 設備管理器 2&#xff09;拔掉所有筆記本外設&#xff08;一定要都拔掉&#xff0c;不然后面禁用設備會混淆&#xff09;&#xff0c;然后右鍵點擊 鍵盤 > HID Keyboard Device 2&#xff09;點擊 更新…

Three.js搭建小米SU7三維汽車實戰(5)su7登場

汽車模型加載 我們在sktechfab上下載的汽車是glb的文件格式&#xff0c;所以使用gltfLoader進行加載。這里將小車直接加載進來看看效果&#xff1b; import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js"; ....其余代碼省略 const gltfLoader new GLT…

ETL怎么實現多流自定義合并?

隨著信息技術的迅猛發展以及數據生成環境的多樣化&#xff0c;互聯網、物聯網和社交媒體的廣泛應用導致各種設備和平臺不斷產生大量數據&#xff0c;需要整合這些數據&#xff0c;從而進行數據融合。數據集成和管理平臺ETLCloud&#xff0c;主要用于支持數據的抽取&#xff08;…

數據結構- 10種常見樹:二叉樹、平衡二叉樹、完全二叉樹

一、樹 樹型結構是一類重要的非線性數據結構。其中以樹和二叉樹最為常用&#xff0c;直觀看來&#xff0c;樹是以分支關系定義的層次結構。把它叫做“樹”是因為它常看起來像一棵倒掛的樹&#xff0c;也就是說它常是根朝上&#xff0c;而葉朝下的。 1.樹的定義&#xff1a; 樹…

Java常用加密方式

一&#xff0c;加密算法分類 對稱加密&#xff1a;指加密和解密的密鑰相同&#xff0c;優點就是加解密的效率高且易于實現。 非對稱加密&#xff1a;指加密和解密的密鑰不相同&#xff0c;也稱為公私要加密。 不可逆加密&#xff1a;特征就是加密過程不需要密鑰&#xff0c;…

SQLite軟件架構與實現源代碼淺析

概述 SQLite 是一個用 C 語言編寫的庫&#xff0c;它成功打造出了一款小型、快速、獨立、具備高可靠性且功能完備的 SQL 數據庫引擎。本文檔將為您簡要介紹其架構、關鍵組件及其協同運作模式。 SQLite 顯著特點之一是無服務器架構。不同于常規數據庫&#xff0c;它并非以單獨進…

讓 Deepseek GPS測速

下面是一個簡單的微信小程序GPS測速功能的實現代碼&#xff0c;包括前端頁面和后端邏輯。 1. 頁面結構 (index.wxml) <view class"container"><view class"speed-display"><text class"speed-value">{{speed}}</text>…

什么是軟件的生命周期,以及常見的開發測試模型

目錄 一、軟件的生命周期 1、什么是生命周期&#xff1f; 2、每個階段都要做些什么&#xff1f; 二、常見的開發模型 1、瀑布模型 2、螺旋模型 3、增量模型、迭代模型 4、敏捷模型 scrum模型 三個角色 五個會議 一、軟件的生命周期 1、什么是生命周期&#xff…

JWT安全:弱簽名測試.【實現越權繞過.】

JWT安全&#xff1a;假密鑰【簽名隨便寫實現越權繞過.】 JSON Web 令牌 (JWT)是一種在系統之間發送加密簽名 JSON 數據的標準化格式。理論上&#xff0c;它們可以包含任何類型的數據&#xff0c;但最常用于在身份驗證、會話處理和訪問控制機制中發送有關用戶的信息(“聲明”)。…

數據分析與應用-----使用scikit-learn構建模型

目錄 一、使用sklearn轉換器處理數據 &#xff08;一&#xff09;、加載datasets模塊中的數據集 &#xff08;二&#xff09;、將數據集劃分為訓練集和測試集 ?編輯 train_test_spli &#xff08;三&#xff09;、使用sklearn轉換器進行數據預處理與降維 PCA 二、 構…

【Tomcat】Tomcat端口僅允許本地訪問設置方法

要設置Tomcat端口僅允許本地訪問&#xff0c;可以通過以下兩種主要方式實現&#xff1a; 方法一&#xff1a;修改Tomcat配置文件&#xff08;推薦&#xff09; 修改 server.xml 文件 打開Tomcat的配置文件 conf/server.xml&#xff0c;找到 <Connector> 標簽&#xff08;…

arcgis字段計算器中計算矢量面的每個點坐標

python腳本 函數 def ExportCoordinates(feat):coors = []partnum = 0partcount = feat.partCountwhile partnum < partcount:part = feat.getPart(partnum)pnt = part.next()while pnt:coors.append("({}, {})".format(pnt.X,pnt.Y))pnt = part.next()if not p…