《初階數據結構》尾聲

目錄

前言:

《快速排序(非遞歸)》:

《歸并排序》:

《歸并排序(非遞歸)》:

《計數排序》:

對于快速排序的優化:

分析:

總結:


前言:

上一篇blog重點講解了《選擇排序》《插入排序》,重點介紹了快速排序的三種方法,這篇blog主要講解《歸并排序》以及它的非遞歸使用方法,最后還會再補充一個計數排序。

上一篇的blog:《插入排序》與《選擇排序》-CSDN博客

《快速排序(非遞歸)》:

typedef int STDataType;typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;void QuickSortNonR(int* a, int begin, int end)
{ST s;STInit(&s);STPush(&s, end);STPush(&s, begin);while (!STEmpty(&s)){int left = STTop(&s);STPop(&s);int right = STTop(&s);STPop(&s);int keyi = PartSort3(a, left, right);//分區間[left, keyi-1] keyi [keyi+1, right]if (keyi + 1 < right){STPush(&s, right);STPush(&s, keyi + 1);}if (left < keyi - 1){STPush(&s, keyi - 1);STPush(&s, left);}}STDestory(&s);
}

我們目前學習數據結構到此,由于我們呢接觸了不少的遞歸操作,不難發現,其實遞歸的算法與棧這個數據結構較為類似。

我們還是一樣先對整體進行排序,分別將begin和end入棧,然后設置好left和right。在第一次對總體排完序后,還是一如既往的會分出兩個區間,我們又需要分別對左右兩個區間進行排序。

在我們利用棧執行代碼的時候要注意先后順序,先入棧的后后訪問,后入棧的先訪問。

《歸并排序》:

歸并排序(MERGE-SORT)是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法(Divide andConquer)的一個非常典型的應用。將已有序的子序列合并,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。

void _MergeSort(int* a, int begin, int end, int* tmp)
{if (begin >= end){return;}int mid = (end + begin) / 2;//[begin, mid] [mid + 1, end]_MergeSort(a, begin, mid, tmp);_MergeSort(a, mid + 1, end, tmp);int begin1 = begin;int end1 = mid;int begin2 = mid + 1;int end2 = end;int i = begin;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2])//<=才是穩定的{tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a + begin, tmp + begin, sizeof(int)* (end - begin + 1));}void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int)* n);if (tmp == NULL){perror("tmp -> malloc");exit(-1);}_MergeSort(a, 0, n - 1, tmp);}

?所謂歸并,就是分而治之。

我們使用遞歸來實現數組的分割和合并,它的邏輯非常像二叉樹的后序遍歷,由于我們要使用遞歸,又要申請臨時空間,所以我們先申請好臨時空間,再將歸并排序過程作為子函數調用,這樣不用在每次遞歸過程申請釋放空間

《歸并排序(非遞歸)》:

我們在快速排序的非遞歸中運用了棧這一數據結構,而我們在實現歸并排序中,不可以去使用棧這一數據結構。

首先我們要知道,如果我們不用棧,我們可以用哪些方法替代,一個我們熟知的方法,是棧,還有一個則是循環。

那么話說回來,為什么不能用棧呢?

對于歸并排序來說,與我們在二叉樹所介紹的后序遍歷較為相似,屬于是“先把每條路走了,再回來說再見”。相比較于快速排序,利用棧是先對總體進行排序,再分區間進行排序。

而歸并排序呢,一上來就把左區間給排完了,那右區間該怎么找呢?出棧后還要在歸并的過程中再次使用出棧后的子區間。

所以我們需要利用循環來進行處理。

我們可以理解我從底層向上拓展,所以我們一開始是1個數據和1個數據進行比較,就像:

我們可以設置一個gap,就像希爾排序那樣,只不過這次我們需要利用這個gap來限制end和begin

我們初始化gap == 1,意思就是兩兩比較,a[0]與a[1]比較分出大小,a[1]與a[2]比較分出大小,最后當下標越界了的時候,我們就可以開始對四個四個之間進行比較,讓gap*=2即可分好下一個小組。

?

void MergeSortNoR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int)* n);if (tmp == NULL){perror("tmp -> malloc");exit(-1);}int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap){int begin1 = i;int end1 = i + gap - 1;int begin2 = i + gap;int end2 = i + 2 * gap - 1;if (end1 >= n || begin1 >= n){break;}if (end2 >= n){end2 = n - 1;}int j = begin1;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}memcpy(a + i, tmp + i, sizeof(int)* (end2 - i + 1));}gap *= 2;}}

《計數排序》:

計數排序又稱為鴿巢原理,是對哈希直接定址法的變形應用。 操作步驟:
1. 統計相同元素出現次數
2. 根據統計的結果將序列回收到原來的序列中

?

void CountSort(int* a, int n)
{int min = a[0];int max = a[0];for (int i = 0; i < n; i++){if (a[i] < min){min = a[i];}if (a[i] > max){max = a[i];}}int range = max - min + 1;int* count = (int*)calloc(range, sizeof(int));//計數for (int i = 0; i < n; i++){count[a[i] - min]++;}//排序int j = 0;for (int i = 0; i < range; i++){while (count[i]--){a[j++] = i + min;}}}

這里我們做了一個優化,假設我們要排序2,3,8888,6666,諸如這樣間隔相差很大的數字,如果不做優化處理就直接calloc新數組,那么會造成許多的空間浪費,所以減去最小值,減小空間的浪費。

這種排序的局限性集中于:

1.不適合分散的數據,適合集中的數據。

2.不適合浮點數、字符串、結構體數據排序,只適合整數。



對于快速排序的優化:

假設每次取的關鍵字key恰好是最大值或者最小值,即數組已經有序,這時的時間復雜度就是O(N^2)

所以我們可以找到最左邊,最右邊,和中間值,進行三數取中,誰不大不小就讓誰做關鍵字并且與第一個數進行交換。

int GetMidi(int* a, int begin, int end)
{int midi = (begin + end) / 2;if (a[midi] < a[begin]){if (a[end] < a[midi]){return midi;}else if (a[begin] < a[end]){return begin;}else{return end;}}else //a[midi]>a[begin]{if (a[end] > a[midi]){return midi;}else if (a[begin] > a[end]){return begin;}else{return begin;}}
}

分析:

?

?

我們可以通過隨機生成100000個數來進行效率的測試。

//測試效率
void TestOp()
{srand(time(0));const int N = 100000;int* a1 = (int*)malloc(sizeof(int)* N);int* a2 = (int*)malloc(sizeof(int)* N);int* a3 = (int*)malloc(sizeof(int)* N);int* a4 = (int*)malloc(sizeof(int)* N);int* a5 = (int*)malloc(sizeof(int)* N);int* a6 = (int*)malloc(sizeof(int)* N);int* a7 = (int*)malloc(sizeof(int)* N);int* a8 = (int*)malloc(sizeof(int)* N);int* a9 = (int*)malloc(sizeof(int)* N);for (int i = 0; i < N; ++i){a1[i] = rand();a2[i] = a1[i];a3[i] = a1[i];a4[i] = a1[i];a5[i] = a1[i];a6[i] = a1[i];a7[i] = a1[i];a9[i] = a1[i];}for (int i = 0; i < N; i++){a8[i] = i;}int begin1 = clock();InsertSort(a1, N);int end1 = clock();int begin2 = clock();ShellSort(a2, N);int end2 = clock();int begin3 = clock();SelectSort(a3, N);int end3 = clock();int begin4 = clock();HeapSort(a4, N);int end4 = clock();int begin5 = clock();QuickSort(a5, 0, N - 1);int end5 = clock();int begin6 = clock();MergeSort(a6, N);int end6 = clock();int begin9 = clock();CountSort(a9, N);int end9 = clock();printf("InsertSort(直接插入排序):%d\n", end1 - begin1);printf("ShellSort(希爾排序):%d\n", end2 - begin2);printf("SelectSort(選擇排序):%d\n", end3 - begin3);printf("HeapSort(堆排序):%d\n", end4 - begin4);printf("QuickSort(快速排序):%d\n", end5 - begin5);printf("MergeSortSort(歸并排序):%d\n", end6 - begin6);printf("CountSort(計數排序):%d\n", end9 - begin9);free(a1);free(a2);free(a3);free(a4);free(a5);free(a6);free(a7);free(a9);
}

?

總結:

?本章到此,數據結構初階的內容就告一段落了,接下來我們逐步講解C++與Linux的各個重點內容。

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

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

相關文章

新疆營盤古城及古墓群安防艙體實施方案

3 總體布局 3.1設計原則 3.1.1執行有效的國家標準、國家軍用標準和行業標準&#xff1b; 3.1.2滿足指標要求&#xff1b; 3.1.3采用通用化、模塊化設計&#xff0c;提高設備可維修性&#xff1b; 3.1.4采用人機工程學知識進行設計&#xff0c;充分考慮安全性。 3.2 總體…

Double-DQN算法

Double-DQN算法的原理簡介、與DQN對比等。 參考深度Q網絡進階技巧 1. 原理簡介 在DQN算法中&#xff0c;雖然有target_net和eval_net&#xff0c;但還是容易出現Q值高估的情況&#xff0c;原因在于訓練時用通過target_net選取最優動作 a ? argmax ? a Q ( s t 1 , a ; w…

51單片機學習(3)-----獨立按鍵控制LED的亮滅狀態

前言&#xff1a;感謝您的關注哦&#xff0c;我會持續更新編程相關知識&#xff0c;愿您在這里有所收獲。如果有任何問題&#xff0c;歡迎溝通交流&#xff01;期待與您在學習編程的道路上共同進步了。 目錄 一. 器件介紹及實驗原理 1.獨立按鍵 &#xff08;1&#xff09;獨…

react 實現路由攔截

簡單介紹下項目背景&#xff0c;我這里做了一個demo&#xff0c;前端使用mock數據&#xff0c;然后實現簡單的路由攔截&#xff0c;校驗session是否包含用戶作為已登錄的依據&#xff0c;react-router-dom是v6。不像vue可以設置登錄攔截beforeenter&#xff0c;react需要我們自…

外包干了3個月,技術退步明顯

先說一下自己的情況&#xff0c;本科生&#xff0c;19年通過校招進入廣州某軟件公司&#xff0c;干了接近4年的功能測試&#xff0c;今年年初&#xff0c;感覺自己不能夠在這樣下去了&#xff0c;長時間呆在一個舒適的環境會讓一個人墮落!而我已經在一個企業干了四年的功能測試…

Linux之用戶和用戶組的深入了解

目錄 一、簡介 1.1、用戶&#xff1a; 1.2、用戶組 1.3、UID和GID 1.3、用戶賬戶分類 查看用戶類別 超級用戶root(0) 程序用戶(1~499) 普通用戶(500~65535) 二、用戶 2.1、添加新的用戶賬號&#xff1a;useradd 2.2、刪除賬號&#xff1a;userdel 有-r與沒有-r區別…

OSDI 2023: Hyrax Fail-in-Place Server Operation in Cloud Platforms

我們使用以下6個分類標準對本文的研究選題進行分析: 1. 硬件故障類型 DRAM: 此類別涉及研究如何處理內存相關的錯誤。這包括單比特錯誤,使用傳統 ECC 進行校正,以及需要冗余、修復技術或隔離故障內存區域的更廣泛的故障。磁盤: 此處研究將解決存儲故障,尤其是 SSD 中的故障…

運維07:堡壘機

什么是跳板機 跳板機就是一臺服務器而已&#xff0c;運維人員在使用管理服務器的時候&#xff0c;必須先連接上跳板機&#xff0c;然后才能去操控內網中的服務器&#xff0c;才能登錄到目標設備上進行維護和操作 開發小張 ---> 登錄跳板機 ---> 再登錄開發服務器 測試…

貸齊樂系統最新版SQL注入(無需登錄繞過WAF可union select跨表查詢)

一、環境 已上傳資源&#xff08;daiqile&#xff09; 二、代碼解釋 1.1Request 不管get請求還是post請求都可以接收到 1.2過濾的還挺多 1.3第二個WAF把數據分為兩個了一個Key一個value&#xff0c;全是explode的功勞 1.4submit是if進入的前提 很明顯走進來了 1.5那我們在這…

學習JAVA的第三天(基礎)

目錄 流程控制語句 順序結構 分支結構 循環結構 分類&#xff1a; 練習 跳轉控制語句 練習 數組 數組介紹 數組的定義和靜態初始化 數組定義 數組的靜態初始化 數組元素訪問 數組遍歷 數組動態初始化 JAVA內存分配 流程控制語句 順序結構 是Java程序默認的執行流程…

UIKit 在 UICollectionView 中拖放交換 Cell 視圖的極簡實現

概覽 UIKit 中的 UICollectionView 視圖是我們顯示多列集合數據的不二選擇&#xff0c;而豐富多彩的交互操作更是我們選擇 UICollectionView 視圖的另一個重要原因。 如上圖所示&#xff1a;我們實現了在 UICollectionView 中拖放交換任意兩個 Cell 子視圖的功能&#xff0c;這…

js如何判斷一個對象中某一個屬性存在并且有值

在JavaScript中&#xff0c;可以使用不同的方法來判斷一個對象中某個屬性是否存在并且有值。以下是幾種常見的方法&#xff1a; 1、使用hasOwnProperty()方法&#xff1a;該方法用于檢查對象是否具有指定的屬性。可以通過以下方式來判斷屬性是否存在并且有值&#xff1a; if (…

整理了去年的一些運維面試題一

Ingress的yaml文件需要包含哪些&#xff1f; CICD搭建流程&#xff1f; JAVA程序打包工具&#xff1f; 如何檢測Linux端口如何通信&#xff1f; k8s集群之間如何通信的&#xff1f; docker組成部分&#xff1f; 20位掩碼有多少主機IP&#xff1f; 在linux中四個T的硬盤使用什…

Zabbix 遠程監控主機

目錄 1、安裝 Zabbix 安裝客戶端 服務端測試通訊 Web頁面添加主機 2、監控 Nginx 自定義腳本監控 Nginx web配置臺 3、監控 MySQL 配置模版文件 配置Web界面 1、安裝 Zabbix node-12 作為zabbix的被監控端&#xff0c;提供mysql服務器&#xff0c;配置zabbix監控node…

jquery寫組件滑動人機驗證組件

jquery組件&#xff0c;雖然 jquery 語法古老&#xff0c;但是寫好了用起來真的很爽啊&#xff0c;本文用滑動人機驗證給大家做個詳細教程&#xff08;直接復制代碼就可以用噢o(*&#xffe3;▽&#xffe3;*)ブ&#xff09; 第一步 先看下組件本身 component.js (function() {…

Nginx網絡服務三-----(三方模塊和內置變量)

1.驗證模塊 需要輸入用戶名和密碼 我們要用htpasswd這個命令&#xff0c;先安裝一下httpd 生成文件和用戶 修改文件 訪問頁面 為什么找不到頁面&#xff1f; 對應的路徑下&#xff0c;沒有這個文件 去創建文件 去虛擬機瀏覽器查看 有的頁面不想被別人看到&#xff0c;可以做…

【UI自動化】使用poco框架進行元素唯一定位

直接選擇&#xff1a; 1.poco(text買入).click() 2.poco("android.widget.ImageView").click()相對選擇、空間選擇&#xff1a; 3.poco(text/name).parent().child()[0].click()正則表達式&#xff1a; 4.listpoco(textMatches".*ETF")今天主要想記錄下…

centos 系統盤 放到 win pc 中的異常解決

有一塊 2.5 480g sata ssd&#xff0c;之前是筆記本電腦的centos系統盤&#xff0c;后來沒用了&#xff0c;打算掛到臺式機上當下載盤。臺式機pc的主板是華碩 h610m-a。 難點一&#xff1a; 因為臺式pc上已經掛了兩塊3.5 hdd&#xff0c;發現sata的電源線都在3.5hdd附近&#…

利用RBI(Remote Browser Isolation)技術訪問ChatGPT

系統組網圖 #mermaid-svg-Bza2puvd8MudMbqR {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Bza2puvd8MudMbqR .error-icon{fill:#552222;}#mermaid-svg-Bza2puvd8MudMbqR .error-text{fill:#552222;stroke:#552222;…

300分鐘吃透分布式緩存-10講:MC是怎么定位key的?

我們在進行 Mc 架構剖析時&#xff0c;除了學習 Mc 的系統架構、網絡模型、狀態機外&#xff0c;還對 Mc 的 slab 分配、Hashtable、LRU 有了簡單的了解。本節課&#xff0c;將進一步深入學習這些知識點。 接下來&#xff0c;進入 Memcached 進階的學習。會講解 Mc 是如何進行…