色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

隊列ADT,實現與使用接口

AGk5_ZLG_zhiyua ? 來源:互聯網 ? 作者:佚名 ? 2017-09-25 16:39 ? 次閱讀

周立功教授數年之心血之作《程序設計與數據結構》以及《面向AMetal框架與接口編程(上)》,電子版已無償性分享到電子工程師與高校群體,在公眾號回復【編程】即可在線閱讀。書本內容公開后,在電子行業掀起一片學習熱潮。經周立功教授授權,本公眾號特對《程序設計與數據結構》一書內容進行連載,愿共勉之。

第三章為算法與數據結構,本文為3.6 隊列ADT。

>>>3.6.1建立抽象

隊列可以簡單的描述為:隊列是一種特殊的容器,其限制插入位置在容器的尾部(隊尾),刪除位置在容器的頭部(隊頭),是一種“先進先出”(First In-First Out,FIFO)的線性結構。比如,排隊買票,人們從隊尾加入隊列,買完票后從隊頭離開(假定沒有人插隊),示意圖詳見圖 3.28。

圖 3.28 隊列示意圖

其抽象定義如下:

  • 類型名:隊列(Queue)

  • 類型屬性:存儲一系列項

  • 類型操作:從隊尾添加項,從隊頭刪除項,確定隊列是否為空,確定隊列是否已滿,確定隊列中的項數。

>>>3.6.2 建立接口

接口是通過頭文件向用戶提供的。首先創建一個頭文件,命名為queue.h。在接口文件中,需要包含兩部分內容:其一,抽象類型queueADT的定義;其二,聲明各隊列ADT的操作函數。

1、定義抽象類型queueADT

與棧類似,使用結構體類型來表示一個隊列,在頭文件中,只需要定義一個該結構體指針類型即可。結構體實際定義的細節、包含的具體成員無需在頭文件中定義,交由具體實現完成對其的定義。定義抽象類型queueADT如下:

2、接口函數聲明

  • 創建隊列

在使用隊列前,必須正確的創建一個隊列,因此需要提供一個用于創建新的queueADT的函數。其函數原型如下:

后置條件:返回隊列。

其調用形式如下:

  • 銷毀隊列

在創建隊列時,具體實現會根據實際情況分配隊列相關的存儲空間,如隊列對象本身的存儲空間,隊列項的存儲空間等。因此,當一個隊列不在使用時,應該釋放掉隊列相關的內存空間,以銷毀一個隊列,銷毀后的隊列不再存在,無法繼續使用。其函數原型如下:

前置條件:queue為之前創建的隊列;

后置條件:釋放隊列相關的所有內存,隊列被銷毀,不再有效。

其調用形式如下:

  • 從隊尾添加項(入隊列)

用戶通過該函數可以從隊列尾部向隊列中添加新元素,其函數原型如下:

前置條件:queue為之前創建的隊列,value是待加入隊尾的數據;

后置條件:如果隊列不滿,將value添加至隊尾,該函數返回true;否則,隊列已滿,隊列保持不變,該函數返回false。

其調用形式如下:

  • 從隊頭移除項(出隊列)

用戶通過該函數可以從隊列頭部移除一個元素,其函數原型如下:

前置條件:queue為之前創建的隊列,p_value為指向存儲“移出隊列的值”的變量的指針;

后置條件:如果隊列不空,將隊頭的值拷貝到*p_value,同時刪除當前隊頭,該函數返回true;否則,隊列為空,該函數返回false。

其調用形式如下:

  • 判斷隊列是否為空

判斷隊列是否為空的函數原型如下:

前置條件:queue為之前創建的隊列;

后置條件:如果隊列為空,則返回true,否則返回false。

其調用形式如下:

  • 判斷隊列是否已滿

判斷隊列是否已滿的函數原型如下:

前置條件:queue為之前創建的隊列;

后置條件:如果隊列為空,則返回true,否則返回false。

其調用形式如下:

  • 確定隊列中元素的個數

確定棧中元素的個數的函數原型如下:

前置條件:queue為之前創建的隊列;

后置條件:返回隊列中元素的個數。

其調用形式如下:

程序清單 3.70 抽象隊列接口(queue.h)

>>>3.6.3 實現與使用接口

在實現隊列之前,首先需要確定使用何種數據存儲結構。一般來說,可以使用地址連續的內存空間存儲數據,比如,使用數組或動態分配一段內存空間;也可以使用地址非連續的鏈表結構存儲數據。

1、順序隊列

在實現隊列之前,我們先來分析一下順序隊列的原理。順序隊列采用連續的內存空間,假定使用front和rear兩個變量來分別表示隊頭和隊尾的位置,初始時,隊列為空,隊頭和隊尾都在為0,詳見圖3.29 (a)。

當從隊尾增加數據時,rear增大向后移動,如data0入隊列后,示意圖詳見圖3.29 (b),此時,隊頭front保持不變,隊尾rear增加1,繼續入隊列,data1、data2、data3入隊列后的示意圖詳見圖3.29 (c)。

圖3.29 隊列示意圖——入隊列

當從隊頭移除數據時,例如,移除data0后,隊頭front指向的數據必須更新為data1,這就有兩種方式:一是front保持不動,將所有數據向前移動一格,如圖3.30(a);二是數據保持不動,front增加1,使其指向data1。顯然,將所有數據向前移動一格存在大量的數據拷貝,隊列中數據越多,數據拷貝操作就越多,效率也就越低,而將front的值加1是非常簡單快捷的,因此,一般來講,都是選擇第二種處理方式。

圖3.30 隊列示意圖——出隊列

按照方式2,繼續將data1、data2、data3出隊列,示意圖詳見圖3.31(a),此時,隊列中不存在任何有效數據,rear與front相等,隊列為空。

若繼續進行數據入隊列操作,data4、data5、data6、data7依次進入隊列后的示意圖詳見圖3.31(b),由于隊列元素已經存儲至最高地址的存儲空間,rear已經指向了無效的地址,這種狀態時,不能再簡單的按照之前的方式,繼續向隊尾添加數據,否則會因為數組越界而導致程序異常。

圖3.31 繼續進行出隊列、入隊列操作

那么,在圖3.31(b)所示的情況下,就不能再添加新元素了嗎?顯然,此時還有一半的空間沒有填充數據,一個將空閑空間利用起來的巧妙方法是:當rear或front的值超過最大值后,自動回滾到0。在圖3.31(b),rear已經超過了最大地址,因此,將其回滾到0,詳見圖3.32(a)。即在邏輯上,將順序隊列視為一個環狀的空間,詳見圖3.32(b)。入隊列后,不再是簡單的將rear值加1,而是當加1后,判斷是否超過了最大地址空間,若超過了,則重新將rear的值設置為0。

圖3.32 循環隊列

將存儲空間視為一個環狀后,將更加方便的理解入隊列和出隊列操作。入隊列時,僅需將數據存儲值rear指向的空間中,存儲完畢后,將rear的值更新為指向下一個存儲單元。出隊列時,將front指向的空間中的數據取出,并將front的值更新為指向下一個存儲單元。

特別地,當front與rear相等時,表示隊列為空,無法進行出隊列操作,與之對應的,什么時候隊列視已滿呢?在圖3.32(b)的基礎上,繼續將data8、data9、data10、data11加入隊列,使所有空閑單元都存儲數據,可以看到加入各個數據后的示意圖詳見圖3.33。

圖3.33 data8~data11依次入隊列

當data11加入隊列后,所有存儲單元都存儲了數據,此時隊列已滿,可以看到,當前的front與rear相等,而隊列為空時,front與rear也相等。由此可見,只憑front與rear是否相等,無法判斷隊列是“滿”還是“空”。如何解決呢?最簡單的方法是增加一個標志,當數據入隊列后,出現front與rear相等時,設置該標志位1,以標志當前是“滿”狀態。而還有一種巧妙的方法,就是實際少用一個存儲單元,當front在rear的下一位置時,即圖3.33(c)所示狀態,就視為隊列已滿,不再允許新元素加入隊列,這種方法的優點是無需增加額外標志,只是將判定隊列是否已滿的方式修改一下,但其缺點也是很明顯的,會浪費一個數據的存儲空間。實際上,額外增加標志時,增加的標志也同樣需要占用內存空間。

至此,分析了入隊列、出隊列、判定隊列是否為空、判定隊列是否為滿的實現方法,還剩下最后一個操作沒有提及,即確定隊列中元素的個數。

而本質上求取元素個數非常簡單,只需要將隊尾值rear減去隊頭值front即可,得到的差值即表示隊頭與隊尾之間的數據個數。但需要考慮特殊情況,因為在循環隊列中,隊尾的值可能小于隊頭的值,如圖3.34(a)、(b)、(c)所示。此時,它們的差值即為負值,如在圖3.35(a)中:rear = 1,front = 4,它們的差值為 -3,而實際元素的個數為5。可見,當值為負數時,只需要將其加上存儲空間的大小(示例中為8)即可。

上面分析了循環隊列的原理,接下來使用程序來實現隊列的各個接口,將實現代碼全部存放在queue.c文件中。在建立接口時,首先在頭文件中定義了抽象隊列的類型為:

這里的結構體類型struct queueCDT只有聲明,還沒有具體的定義。因此無論何種實現方式,都需要先實現struct queueCDT類型的定義。

假定使用的連續空間通過malloc動態分配得到,則在結構體中需要包含一個指向連續空間首地址的指針,以便使用這片內存空間。此外,在上面原理的分析中,需要使用front和rear分別表示隊頭和隊尾的位置,因此隊列結構體中需要包含這兩個成員,定義隊列結構體類型為:

理解了隊列各種操作的原理后,則實現起來就較為容易了,詳見程序清單 2.34。

程序清單3.71 順序隊列的實現(queue.c)

在getQueueLength()函數的實現中,巧妙地避免了使用if語句判斷rear和front的差值是否為負值,差值無論正負,都加上了MAXQSIZE(隊列的容量大小)。此時,若差值為負值,則可以得到正確的結果,但若差值為正值,則結果會恰好多出MAXQSIZE,因此最后需要將結果對MAXQSIZE取余,以丟棄可能多出的MAXQSIZE,確保了結果的正確性。

2、鏈隊列

在鏈隊列中,各個數據的存儲空間可以不連續,基于鏈表的隊列(假定數據域為int類型)示意圖詳見圖3.36。

圖3.36 鏈隊列示意圖

需要注意的是,鏈表頭結點代表的是鏈表頭,為了方便添加結點操作而定義的,不攜帶有效的應用數據。其后的結點才是有效結點,因此隊頭是第一個有效的數據結點,隊尾是最后一個有效的數據結點。

入隊列即將新元素添加至鏈表尾部,出隊列就是移除第一個數據結點。這些操作在鏈表程序中都已經有相應的接口。因此基于之前的鏈表程序,實現鏈隊列非常容易。在隊列結構體中,僅需包含鏈表頭結點,無需front、rear等成員。定義隊列結構體類型為:

若隊列中各個結點的數據類型為int類型,則對應的鏈表結點類型為:

如程序清單3.72所示為一種鏈隊列的實現范例。

程序清單3.72 鏈隊列的實現(queue_list.c)

對于大多數操作而言,鏈表都已經提供了相應的接口,因此入隊列、出隊列、判斷滿或空都非常容易。稍微復雜點的是得到隊列中的元素個數,其需要遍歷整個鏈表,每遍歷到一個結點時,都將計數器count的值加1(count的地址通過遍歷函數的p_arg參數傳遞),遍歷結束后,計數器的值即為隊列中的元素個數。

在入隊列函數的實現中,每次都需要將新的結點添加至鏈表尾部,而對于單向鏈表,直接將結點添加至鏈表尾部的效率是非常低的,每次都需要從頭開始遍歷,直到找到最后一個結點,才能執行實際的添加操作。如何解決這個問題呢?最簡單的辦法是使用雙向鏈表,但雙向鏈表需要占用更多內存,同時,在隊列的實現中,并不需要雙向鏈表那么靈活,不需要隨意的尋找上一個結點,顯然,這里使用雙向鏈表有點“小題大做”了。把握到一個核心的問題,就是需要將新結點添加至鏈表尾部,如果使用一個指針p_rear來指向尾結點,那么,添加結點至鏈表尾部時,可以直接將結點添加至p_rear指向的結點后面,無需再從頭開始遍歷鏈表,即“slist_add (p_head, p_rear, p_node);”。

添加結束后,新的p_node結點為新的尾結點,因此需要更新p_rear的值,使其指向新的尾結點,即“p_rear = p_node;”。p_rear可以作為隊列結構體的一個成員,以便使用。讀者可以按照這種方式,自行嘗試修改入隊列函數,提升入隊列的效率。

對于使用者來講,無需關心隊列的具體實現方式。只要正確把握接口的使用方法(前置條件和后置條件),就可以編寫使用隊列的應用程序。將整數入隊列,再出隊列的范例程序詳見程序清單 2.35。

程序清單3.73 使用隊列接口的范例程序


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 程序
    +關注

    關注

    117

    文章

    3785

    瀏覽量

    81004
  • 周立功
    +關注

    關注

    38

    文章

    130

    瀏覽量

    37616

原文標題:周立功:隊列ADT——實現與使用接口

文章出處:【微信號:ZLG_zhiyuan,微信公眾號:ZLG致遠電子】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    FIFO隊列原理簡述

    FIFO是隊列機制中最簡單的,每個接口上只有一個FIFO隊列,表面上看FIFO隊列并沒有提供什么QoS保證,甚至很多人認為FIFO嚴格意義上不算做一種
    發表于 07-10 09:22 ?1656次閱讀

    實現隊列環形緩沖的方法

    串口隊列環形緩沖區隊列串口環形緩沖的好處代碼實現隊列??要實現隊列環形緩沖,還需要一定的數據結構
    發表于 02-21 07:11

    ADT6501/ADT6502/ADT6503/ADT650

    The ADT6501/ADT6502/ADT6503/ADT6504 are trip point temperature switches available in a 5-lea
    發表于 08-23 20:50 ?27次下載

    ADT6501/ADT6502/ADT6503/ADT650

    ADT6501/ADT6502/ADT6503/ADT6504 低成本2.7V至5.5 V,微溫度開關 采用SOT-23封裝 ADT650
    發表于 08-23 20:52 ?1247次閱讀
    <b class='flag-5'>ADT</b>6501/<b class='flag-5'>ADT</b>6502/<b class='flag-5'>ADT</b>6503/<b class='flag-5'>ADT</b>650

    adt6501/adt6502/adt6503/adt6504采用SOT-23微溫度開關數據表

    The ADT6501/ADT6502/ADT6503/ADT6504 are trip point temperature switches available in a 5-lea
    發表于 09-27 16:15 ?5次下載
    <b class='flag-5'>adt</b>6501/<b class='flag-5'>adt</b>6502/<b class='flag-5'>adt</b>6503/<b class='flag-5'>adt</b>6504采用SOT-23微溫度開關數據表

    AN-1250: ADT7310/ADT7410與基于Cortex-M3的精密模擬微控制器(ADuCM360)的接口

    AN-1250: ADT7310/ADT7410與基于Cortex-M3的精密模擬微控制器(ADuCM360)的接口
    發表于 03-21 09:05 ?12次下載
    AN-1250: <b class='flag-5'>ADT</b>7310/<b class='flag-5'>ADT</b>7410與基于Cortex-M3的精密模擬微控制器(ADuCM360)的<b class='flag-5'>接口</b>

    EVAL-ADT7470EB:ADT7470評估板

    EVAL-ADT7470EB:ADT7470評估板
    發表于 05-14 15:32 ?0次下載
    EVAL-<b class='flag-5'>ADT</b>7470EB:<b class='flag-5'>ADT</b>7470評估板

    深度解析數據結構與算法篇之隊列及環形隊列實現

    的位置。 02 — 環形隊列實現 要想將元素放入隊列我們必須知道對頭和隊尾,在隊列長度不能無限大的條件下我們還要知道隊列的最大容量,我們還
    的頭像 發表于 06-18 10:07 ?1923次閱讀

    實現一個雙端隊列的步驟簡析

    隊列是非常基礎且重要的數據結構,雙端隊列屬于隊列的升級。很多的算法都是基于隊列實現,例如搜索中的bfs,圖論中的spfa,計算幾何中的me
    的頭像 發表于 10-27 18:11 ?1440次閱讀

    什么是消息隊列?消息隊列中間件重要嗎?

    應用解耦:消息隊列減少了服務之間的耦合性,不同的服務可以通過消息隊列進行通信,而不用關心彼此的實現細節。
    的頭像 發表于 11-07 14:55 ?1411次閱讀

    嵌入式環形隊列和消息隊列實現

    嵌入式環形隊列和消息隊列實現數據緩存和通信的常見數據結構,廣泛應用于嵌入式系統中的通信協議和領域。
    的頭像 發表于 04-14 11:52 ?1553次閱讀

    嵌入式環形隊列和消息隊列是如何去實現的?

    嵌入式環形隊列和消息隊列實現數據緩存和通信的常見數據結構,廣泛應用于嵌入式系統中的通信協議和領域。
    發表于 05-20 14:55 ?1129次閱讀

    單片機消息隊列實現原理和機制

    單片機開發過程中通常會用到“消息隊列”,一般實現的方法有多種。 本文給大家分享一下隊列實現的原理和機制。
    的頭像 發表于 05-26 09:50 ?1547次閱讀
    單片機消息<b class='flag-5'>隊列</b>的<b class='flag-5'>實現</b>原理和機制

    RTOS消息隊列的應用

    基于RTOS的應用中,通常使用隊列機制實現任務間的數據交互,一個應用程序可以有任意數量的消息隊列,每個消息隊列都有自己的用途。
    發表于 05-29 10:49 ?629次閱讀
    RTOS消息<b class='flag-5'>隊列</b>的應用

    嵌入式環形隊列與消息隊列實現原理

    嵌入式環形隊列,也稱為環形緩沖區或循環隊列,是一種先進先出(FIFO)的數據結構,用于在固定大小的存儲區域中高效地存儲和訪問數據。其主要特點包括固定大小的數組和兩個指針(頭指針和尾指針),分別指向隊列的起始位置和結束位置。
    的頭像 發表于 09-02 15:29 ?478次閱讀
    主站蜘蛛池模板: 国产免费久久爱久久啪| 抽插H浊水H嫩B父皇| 88.7在线收听| 99re在线播放| 超碰在线线公开免费视频| 国产精品久久久久精品A片软件| 国产乱码卡二卡三卡4W| 精品国产乱码久久久久久乱码| 久久只有这里有精品4| 男人的天堂色| 忘忧草下载| 野花社区视频WWW高清| 99精品观看| 国产高清美女一级毛片久久| 姐姐不~不可以动漫在线观看| 伦理在线影院伦理电影| 人妻系列合集| 亚洲欧洲一级| 99久久99久久精品国产片果冻| 国产精品99精品无码视亚| 久久国产免费| 人人插人人射| 亚洲欧洲日韩天堂无吗| wankz tv videos国产| 国产一区免费在线观看| 男女交性视频无遮挡全过程| 偷窥 亚洲 色 国产 日韩| 在教室伦流澡到高潮H女攻视频 | FREE乌克兰嫩交HD| 国产精品久久自在自2021 | 国产亚洲国际精品福利| 老阿姨儿子一二三区| 色小说在线| 在线播放国产视频| 国产成人精品久久一区二区三区 | 色偷偷888欧美精品久久久| 亚洲一区二区三区91| 超熟女专门志| 久久婷婷久久一区二区三区| 熟女人妻-蜜臀AV-首页| 18禁黄久久久AAA片|