笨辦法學(xué)C 練習(xí)42:棧和隊(duì)列

練習(xí)42:棧和隊(duì)列

原文:Exercise 42: Stacks and Queues

譯者:飛龍

到現(xiàn)在為止死遭,你已經(jīng)知道了大多數(shù)用于構(gòu)建其它數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu)洲守。如果你擁有一些List潘明、DArray誊爹、HashmapTree怠晴,你就能用他們構(gòu)造出大多數(shù)其它的任何結(jié)構(gòu)熄诡。你碰到的其它任何結(jié)構(gòu)要么可以用它們實(shí)現(xiàn),要么是它們的變體鳄虱。如果不是的話弟塞,它可能是外來的數(shù)據(jù)結(jié)構(gòu),你可能不需要它拙已。

StackQueue是非常簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)决记,它們是List的變體。它們是List的弱化或者轉(zhuǎn)換形式倍踪,因?yàn)槟阒恍枰?code>List的一端放置元素系宫。對(duì)于Stack,你只能能夠在一段壓入和彈出元素建车。而對(duì)于Queue扩借,你只能夠在開頭壓入元素,并在末尾彈出(或者反過來)缤至。

我能夠只通過C預(yù)處理器和兩個(gè)頭文件來實(shí)現(xiàn)這兩個(gè)數(shù)據(jù)結(jié)構(gòu)潮罪。我的頭文件只有21行的長度,并且實(shí)現(xiàn)了所有StackQueue的操作领斥,不帶有任何神奇的定義嫉到。

我將會(huì)向你展示單元測(cè)試,你需要實(shí)現(xiàn)頭文件來讓它們正常工作月洛。你不能創(chuàng)建stack.cqueue.c實(shí)現(xiàn)文件來通過測(cè)試何恶,只能使用stack.hqueue.h來使測(cè)試運(yùn)行。

#include "minunit.h"
#include <lcthw/stack.h>
#include <assert.h>

static Stack *stack = NULL;
char *tests[] = {"test1 data", "test2 data", "test3 data"};
#define NUM_TESTS 3


char *test_create()
{
    stack = Stack_create();
    mu_assert(stack != NULL, "Failed to create stack.");

    return NULL;
}

char *test_destroy()
{
    mu_assert(stack != NULL, "Failed to make stack #2");
    Stack_destroy(stack);

    return NULL;
}

char *test_push_pop()
{
    int i = 0;
    for(i = 0; i < NUM_TESTS; i++) {
        Stack_push(stack, tests[i]);
        mu_assert(Stack_peek(stack) == tests[i], "Wrong next value.");
    }

    mu_assert(Stack_count(stack) == NUM_TESTS, "Wrong count on push.");

    STACK_FOREACH(stack, cur) {
        debug("VAL: %s", (char *)cur->value);
    }

    for(i = NUM_TESTS - 1; i >= 0; i--) {
        char *val = Stack_pop(stack);
        mu_assert(val == tests[i], "Wrong value on pop.");
    }

    mu_assert(Stack_count(stack) == 0, "Wrong count after pop.");

    return NULL;
}

char *all_tests() {
    mu_suite_start();

    mu_run_test(test_create);
    mu_run_test(test_push_pop);
    mu_run_test(test_destroy);

    return NULL;
}

RUN_TESTS(all_tests);

之后是queue_tests.c嚼黔,幾乎以相同的方式來使用Queue

#include "minunit.h"
#include <lcthw/queue.h>
#include <assert.h>

static Queue *queue = NULL;
char *tests[] = {"test1 data", "test2 data", "test3 data"};
#define NUM_TESTS 3


char *test_create()
{
    queue = Queue_create();
    mu_assert(queue != NULL, "Failed to create queue.");

    return NULL;
}

char *test_destroy()
{
    mu_assert(queue != NULL, "Failed to make queue #2");
    Queue_destroy(queue);

    return NULL;
}

char *test_send_recv()
{
    int i = 0;
    for(i = 0; i < NUM_TESTS; i++) {
        Queue_send(queue, tests[i]);
        mu_assert(Queue_peek(queue) == tests[0], "Wrong next value.");
    }

    mu_assert(Queue_count(queue) == NUM_TESTS, "Wrong count on send.");

    QUEUE_FOREACH(queue, cur) {
        debug("VAL: %s", (char *)cur->value);
    }

    for(i = 0; i < NUM_TESTS; i++) {
        char *val = Queue_recv(queue);
        mu_assert(val == tests[i], "Wrong value on recv.");
    }

    mu_assert(Queue_count(queue) == 0, "Wrong count after recv.");

    return NULL;
}

char *all_tests() {
    mu_suite_start();

    mu_run_test(test_create);
    mu_run_test(test_send_recv);
    mu_run_test(test_destroy);

    return NULL;
}

RUN_TESTS(all_tests);

你應(yīng)該在不修改測(cè)試文件的條件下细层,使單元測(cè)試能夠運(yùn)行,并且它應(yīng)該能夠通過valgrind而沒有任何內(nèi)存錯(cuò)誤唬涧。下面是當(dāng)我直接運(yùn)行stack_tests時(shí)它的樣子:

$ ./tests/stack_tests
DEBUG tests/stack_tests.c:60: ----- RUNNING: ./tests/stack_tests
----
RUNNING: ./tests/stack_tests
DEBUG tests/stack_tests.c:53: 
----- test_create
DEBUG tests/stack_tests.c:54: 
----- test_push_pop
DEBUG tests/stack_tests.c:37: VAL: test3 data
DEBUG tests/stack_tests.c:37: VAL: test2 data
DEBUG tests/stack_tests.c:37: VAL: test1 data
DEBUG tests/stack_tests.c:55: 
----- test_destroy
ALL TESTS PASSED
Tests run: 3
$

queue_test的輸出基本一樣今艺,所以我在這里就不展示了。

如何改進(jìn)

你可以做到的唯一真正的改進(jìn)爵卒,就是把所用的List換成DArrayQueue數(shù)據(jù)結(jié)構(gòu)難以用DArray實(shí)現(xiàn)撵彻,因?yàn)樗瑫r(shí)處理兩端的節(jié)點(diǎn)钓株。

完全在頭文件中來實(shí)現(xiàn)它們的缺點(diǎn)实牡,是你并不能夠輕易地對(duì)它做性能調(diào)優(yōu)。你需要使用這種技巧轴合,建立一種以特定的方式使用List的“協(xié)議”创坞。做性能調(diào)優(yōu)時(shí),如果你優(yōu)化了List受葛,這兩種數(shù)據(jù)結(jié)構(gòu)都會(huì)有所改進(jìn)题涨。

附加題

  • 使用DArray代替List實(shí)現(xiàn)Stack,并保持單元測(cè)試不變总滩。這意味著你需要?jiǎng)?chuàng)建你自己的STACK_FOREACH纲堵。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市闰渔,隨后出現(xiàn)的幾起案子席函,更是在濱河造成了極大的恐慌,老刑警劉巖冈涧,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茂附,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡督弓,警方通過查閱死者的電腦和手機(jī)营曼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愚隧,“玉大人蒂阱,你說我怎么就攤上這事〖楣ィ” “怎么了蒜危?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長睹耐。 經(jīng)常有香客問我辐赞,道長,這世上最難降的妖魔是什么硝训? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任响委,我火速辦了婚禮,結(jié)果婚禮上窖梁,老公的妹妹穿的比我還像新娘赘风。我一直安慰自己,他們只是感情好纵刘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布邀窃。 她就那樣靜靜地躺著,像睡著了一般假哎。 火紅的嫁衣襯著肌膚如雪瞬捕。 梳的紋絲不亂的頭發(fā)上鞍历,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音肪虎,去河邊找鬼劣砍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛扇救,可吹牛的內(nèi)容都是我干的刑枝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼迅腔,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼装畅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起钾挟,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤洁灵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后掺出,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徽千,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年汤锨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了双抽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡闲礼,死狀恐怖牍汹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柬泽,我是刑警寧澤慎菲,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站锨并,受9級(jí)特大地震影響露该,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜第煮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一解幼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧包警,春花似錦撵摆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春苟呐,著一層夾襖步出監(jiān)牢的瞬間痒芝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工牵素, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人澄者。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓笆呆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親粱挡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赠幕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容