主頁 > 軟體設計 > 都中秋了還在苦苦加班排序?這篇文章讓你一次性搞定排序問題,手把手教你實作一個通用的排序函式

都中秋了還在苦苦加班排序?這篇文章讓你一次性搞定排序問題,手把手教你實作一個通用的排序函式

2021-09-22 10:30:56 軟體設計

大家好呀,今天是中秋佳節,大家都回家和家人團聚了嗎?

今年的月餅好吃嗎?

不管怎么樣,博主都在這里祝大家中秋節快樂~~

今天我們就來寫一個功能強大的通用型別排序函式吧!

【手把手教你實作】通用排序函式

  • 原型
  • 思想
  • 代碼實作
    • 1、確定冒泡排序的趟數
    • 2.確定一趟冒泡排序中兩兩比較的次數
    • 3. 兩兩比較
    • 4. 交換
  • 總結

每次我們寫一個不同型別的排序的時候,我們都要寫重新寫一個新的排序函式,那么有沒有什么方法,可以寫一個適用于所有型別的排序函式呢?

當然是有的!接下來我們就一起來看看吧~

原型

首先我們知道庫函式中有一個qsort函式,它其實就適用于任何型別的資料,

(不要問我為什么已經有了qsort函式還非要自己寫一個,我知道你們都跟我一樣熱愛學習,必須要自己寫出來才肯罷休!)
在這里插入圖片描述
所以,作為我們的通用排序函式的原型,我們首先要搞懂別人(qsort)是怎么做到“通用”的,只用把別人的工具弄明白了,我們才能寫出屬于自己的工具,

首先我們再cplusplus網站中看看qsort這個函式的真容,

在這里插入圖片描述
首先我們看到第一個引數是一個指標,指標的型別是void*,這表示可以接收任意型別的指標,包括整型指標、字符指標、浮點型指標、結構體指標等等,

這樣,我們在傳參的時候就可以把任意型別的陣列作為引數傳給qsort,達到一個通用的方式,

后面的引數分別是size_t num、size_t size和
int (compar)(const void,const void*)),它們分別是什么意思呢?我們可以帶著疑問和猜測繼續往下看,

在這里插入圖片描述

看到這里,我們應該大概知道,這個函式可以實作通用排序的原理,

我們先接收一個指向被排序的陣列的指標,然后告訴函式我們要排序的資料的數量以及每個元素的大小,最后再告訴函式這些資料之間應該怎么排序,然后剩下的交給函式按照我們的規則和要求去執行就可以了,

那么下面我們就先用qsort函式來實作排序,

首先我們把一個int陣列arr由降序排為升序,
在這里插入圖片描述
那么除了給整型陣列、字符陣列等等我們常見的陣列之外,我們嘗試著用qsort給結構體進行排序,

首先我們創建一個結構體,在這個結構體型別之上創建相應的變數并初始化,
在這里插入圖片描述
注意:上圖中為了方便,我直接把struct student型別重定義為s,

下面如果我們想要按照名字對arrs進行排序:
在這里插入圖片描述
或者按照年齡排序進行排序:
在這里插入圖片描述
其實也可以按照id排序,這里我就不寫了,大家可以自行實作哦(其實陣列中已經排成升序了,大家可以把它排成降序),

思想

從原型qsort中,我們知道了實作一個通用排序函式的原理,但是函式內部究竟應該如何實作排序的呢?

我們可以利用之前我們學過的一個排序思想:冒泡排序,來實作排序函式內部的排序方法,

詳見這篇文章:【手把手帶你入門】陣列的創建與使用(超詳細解釋,包括陣列傳參以及陣列名的理解)
在這里插入圖片描述
我們知道,冒泡排序的思想是每一次讓相鄰兩個元素進行比較,一趟冒泡排序可以讓一個元素來到它應在的位置上,

我們還是先來看看我們之前用來實作的冒泡排序函式,
在這里插入圖片描述
我們可以看到,通過冒泡排序實作排序的重點主要有4點:

  1. 確定冒泡排序的趟數:被排序元素的個數-1
  2. 確定一趟冒泡排序中兩兩比較的次數:剩余要排序的元素個數-1
  3. 兩兩比較
  4. 交換

明確了思想,我們就可以寫代碼啦!

代碼實作

首先我們一局qsort函式寫出my_sort函式的使用,
在這里插入圖片描述
再依此(或者qsort函式)寫出my_sort函式的封裝,
在這里插入圖片描述

1、確定冒泡排序的趟數

在這里插入圖片描述

2.確定一趟冒泡排序中兩兩比較的次數

在這里插入圖片描述

3. 兩兩比較

這里的兩兩比較就要根據不同型別用不同的比較方法,所以我們要用到之前傳給我們的比較函式,

按照排成升序的原則,如果比較函式回傳值<=0,則不進行交換;如果>0,則執行兩個元素的交換,
在這里插入圖片描述

這里要注意,我們為什么把void*強制轉換成字符指標型別而不是整型指標型別等等?

因為,我們傳給函式的指標有可能是各個型別的指標,而不同型別的指標依次能跳過的記憶體步長是不一樣的,為了能夠遍歷不同型別元素中的每個位元組,我們應該用步長最小的字符指標型別來對元素進行小步多次的訪問,

這就好像我們從家里去學校選擇交通工具,我們可以選擇步行、公交、或者打車,打車雖然很方便,上車之后下一站就到目的地了,但是一路上我們就不能停下來;如果選擇公交,那么我們到一站就會停下來一次,這樣在路途中能看到的風景就更多更詳細;而如果選擇走路,那么我們想在哪里停下來就在哪里停下來,這樣我們就能完整地看到整個從家里到學校的所有路上的風景,

所以,這里(包括后面的交換)為了能夠完整地訪問元素中的內容,我們采用的是最小步長的char*指標,以防“步子”走太快,錯過了一些重要的“風景”,

4. 交換

在這里插入圖片描述

因為每次都是交換一個位元組的大小,所以我們要根據一個元素包含的位元組數來確定一次元素的交換需要交換幾個位元組,
在這里插入圖片描述
在這里插入圖片描述
這樣,一個通用排序函式就寫完啦!

接下來,我們來驗證一下它的可行性吧!

在這里插入圖片描述
在監視視窗中,可以看到arr陣列從降序被排成了升序,

雖然已經初步證明了排序函式的實作,但是我們還是再次用上面寫過的結構體來驗證一下吧!

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

從除錯的結果來看,我們的通用排序函式已經很好地實作啦!!!太棒啦~~~~

你學廢了嗎?

在這里插入圖片描述

但是,等一等,回顧我們的代碼,我們還是可以再完善一下我們的代碼的!

在這里插入圖片描述
我們發現,最初傳參的時候,num和size的型別都是size_t,其實就是unsigned int,所以我們后面在進行運算(比較)的時候,要注意變數之間型別的同一,避免編譯器警告噢~

所以這里,博主對代碼進行了修改,把代碼中的i、j等變數改成了size_t型別,
在這里插入圖片描述
大家也要注意這些小細節噢!

雖然它們并不起眼,但是有時候很可能是決定問題的關鍵呢!

同一的代碼不僅能減少錯誤的發生,代碼讀起來也會更好,所以,我們都要不怕麻煩,向著完美進發噢!!!

在這里插入圖片描述

總結

其實這個通用冒泡排序看似很復雜,但是寫下來好像也并不是很難呢!當然qsort函式內部并不一定是以冒泡排序的演算法來對元素進行排列的,當然感興趣的朋友們也可以去研究一下!

以下是博主寫完通用排序函式之后的一點總結和感悟:

  1. 我們的通用排序函式主要指的是型別通用,那么實作型別通用的一個關鍵因素在于比較函式,這里就依賴于回呼函式的存在,
    我們不是自己直接去呼叫比較函式,而是通過這個通用排序函式來呼叫它,告訴它有這個函式,讓它自己去呼叫,

  2. 我們可以發現,指標在函式傳參中的應用非常普遍,有了各種型別的指標之后,我們就可以通過傳參把變的地方告訴函式,不變的地方讓函式來幫助我們完成,這樣在寫一些明顯有重復的地方的時候,我們就可以用函式來替代那么重復,

  3. 思考通用排序函式完成的程序中,我們可以得到一種學習方法:先找到一個現有的東西,弄懂它的內涵,然后模仿它,在模仿的程序中,結合我們已經學過的內容,來實作一個自己的東西,我覺得這是一個非常好的學習和創造方法,不僅適用于代碼,更可用于我們生活學習中的方方面面,必須mark下來,

  4. 其實博主在寫代碼的程序中,并不是一帆風順,很容易在小地方出錯,然后找bug找了好久好久,最后發現是在一個很小很小的地方不小心把j寫成了i,所以寫代碼的時候一定要十分細心,遇到問題的時候,一定耐心一個字母一個字母地看,如果有錯誤提示,要根據錯誤提示思考可能出錯的地方,這樣有方向地找bug,效率會高很多,

  5. 最后,寫代碼不是一個一蹴而就的事情,我們寫完代碼之后,要回過頭來再驗證一下,再看看還有哪里可以更完美~每一次的更改會給下一次代碼更多減少錯誤和麻煩的經驗,

最最最最后,感謝友友們那么耐心地看到這里,如果你覺得我的文章對你有用,記得點贊收藏關注一波,在評論區留下你的腳印噢~

在這里插入圖片描述

關注我,一起精進C語言吧~

本文代碼已經上傳到gitee啦~大家按需自取哦!
https://gitee.com/fang-qiuhui/my-code/blob/0167e797c445f809c626cfce2ead57fa31d69392/blog_2021_9_20_qsort/blog_2021_9_20_qsort.c

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/301997.html

標籤:其他

上一篇:高校的監控、有線、無線網路業務如何跑起來?

下一篇:?? 中秋佳節相約C語言進階 ?? 字串函式與記憶體函式 【建議收藏】

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more