隊(duì)列(鏈隊(duì)列)

隊(duì)列:只允許在一端進(jìn)行插入陪腌,在另一端進(jìn)行刪除的線性表烹骨。

鏈隊(duì)列:使用鏈表實(shí)現(xiàn)的隊(duì)列缆瓣;具有隊(duì)頭指針和隊(duì)尾指針喧枷,指示隊(duì)列元素所在的位置。

鏈隊(duì)列特性:

  • 只能隊(duì)尾插入元素弓坞、在隊(duì)頭刪除元素隧甚。
  • 先進(jìn)先出(First In First Out)的線性表,先進(jìn)入的元素出隊(duì)渡冻,后進(jìn)入的元素才能出隊(duì)戚扳。

優(yōu)點(diǎn):

  • 相比普通的隊(duì)列,元素出隊(duì)時(shí)無需移動(dòng)大量元素族吻,只需移動(dòng)頭指針帽借。
  • 可動(dòng)態(tài)分配空間,不需要預(yù)先分配大量存儲(chǔ)空間超歌。
  • 適合處理用戶排隊(duì)等待的情況砍艾。

缺點(diǎn):

  • 需要為表中的邏輯關(guān)系增加額外的存儲(chǔ)空間。

時(shí)間復(fù)雜度

  • 讀取時(shí)的時(shí)間復(fù)雜度為O(1)巍举。
  • 插入辐董、刪除時(shí)的時(shí)間復(fù)雜度為O(1)。
隊(duì)列示意圖
空鏈隊(duì)列示意圖
鏈隊(duì)列插入元素示意圖
鏈隊(duì)列刪除元素示意圖

實(shí)現(xiàn)代碼如下:

// 隊(duì)列(鏈隊(duì)列)
#include <stdio.h>
#include <malloc.h>
#include <math.h>

#define OK 1      // 執(zhí)行成功
#define ERROR 0   // 執(zhí)行失敗
#define TRUE 1    // 返回值為真
#define FALSE 0   // 返回值為假

typedef int Status; // 函數(shù)返回結(jié)果類型
typedef int ElemType; // 元素類型

// 隊(duì)列節(jié)點(diǎn)
typedef struct QNode {
    ElemType data; // 元素值
    struct QNode *next; // 指向下一個(gè)節(jié)點(diǎn)的指針
} QNode, *QueuePtr;

// 鏈隊(duì)列結(jié)構(gòu)
typedef struct {
    QueuePtr front, rear; // 隊(duì)頭指針禀综、隊(duì)尾指針
} LinkQueue;

/**
 * 初始化隊(duì)列
 * @param Q 隊(duì)列
 * @return 執(zhí)行狀態(tài)
 */
Status InitQueue(LinkQueue *Q) {
    // 為隊(duì)頭和隊(duì)尾指針分配內(nèi)存
    Q->front = Q->rear = (QueuePtr) malloc(sizeof(QNode));

    // 內(nèi)存分配失敗简烘,結(jié)束程序
    if (!Q->front || !Q->rear) {
        exit(OVERFLOW);
    }

    Q->front->next = NULL; // 隊(duì)頭節(jié)點(diǎn)指向NULL
    return OK;
}

/**
 * 銷毀隊(duì)列
 * @param Q 隊(duì)列
 * @return 執(zhí)行狀態(tài)
 */
Status DestroyQueue(LinkQueue *Q) {
    // 當(dāng)隊(duì)列中還有元素
    while (Q->front) {
        Q->rear = Q->front->next;// 隊(duì)尾指針指向隊(duì)頭指針的下一個(gè)元素
        free(Q->front); // 釋放隊(duì)頭指針?biāo)诠?jié)點(diǎn)
        Q->front = Q->rear; // 隊(duì)頭指針指向隊(duì)尾指針(即原來的下一個(gè)元素)
    }
    return OK;
}

/**
 * 清空隊(duì)列
 * @param Q 隊(duì)列
 * @return 執(zhí)行狀態(tài)
 */
Status ClearQueue(LinkQueue *Q) {
    QueuePtr p, q; // p用來遍歷隊(duì)列節(jié)點(diǎn)苔严,q用來指向被刪除的節(jié)點(diǎn)

    Q->rear = Q->front; // 隊(duì)尾指針指向隊(duì)頭指針
    p = Q->front->next; // p指向隊(duì)頭指針的下一個(gè)節(jié)點(diǎn)
    Q->front->next = NULL; // 隊(duì)頭指針的下一個(gè)節(jié)點(diǎn)指向NULL(表示刪除之后的所有元素)

    // 當(dāng)隊(duì)列中還有元素,釋放頭節(jié)點(diǎn)之后的所有節(jié)點(diǎn)
    while (p) {
        q = p; // q節(jié)點(diǎn)指向被刪除節(jié)點(diǎn)
        p = p->next; // p指向隊(duì)列的下一個(gè)節(jié)點(diǎn)
        free(q); // 釋放q節(jié)點(diǎn)
    }
    return OK;
}

/**
 * 判斷隊(duì)列是否為空
 * @param Q 隊(duì)列
 * @return 隊(duì)列是否為空
 */
Status QueueEmpty(LinkQueue Q) {
    // 頭指針和尾指針位置相等孤澎,隊(duì)列為空
    if (Q.front == Q.rear) {
        return TRUE;
    } else {
        return FALSE;
    }
}

/**
 * 獲取隊(duì)列長(zhǎng)度
 * @param Q 隊(duì)列
 * @return 隊(duì)列長(zhǎng)度
 */
int QueueLength(LinkQueue Q) {
    int i = 0; // 用于統(tǒng)計(jì)隊(duì)列長(zhǎng)度的計(jì)數(shù)器
    QueuePtr p; // 用于遍歷隊(duì)列的元素
    p = Q.front; // p指向隊(duì)頭節(jié)點(diǎn)

    // 當(dāng)p沒有移動(dòng)到隊(duì)尾指針位置
    while (p != Q.rear) {
        i++; // 計(jì)數(shù)器加1
        p = p->next; // p移動(dòng)到隊(duì)列的下一個(gè)節(jié)點(diǎn)
    }
    return i; // 返回隊(duì)列長(zhǎng)度
}

/**
 * 獲取隊(duì)列頭元素
 * @param Q 隊(duì)列
 * @param e 存儲(chǔ)頭元素值
 * @return 執(zhí)行狀態(tài)
 */
Status GetHead(LinkQueue Q, ElemType *e) {
    QueuePtr p;

    // 隊(duì)列為空届氢,獲取失敗
    if (Q.front == Q.rear) {
        return ERROR;
    }

    p = Q.front->next; // p指向隊(duì)列的第一個(gè)元素
    *e = p->data; // 將隊(duì)列頭元素的值賦值給e元素
    return OK;
}

/**
 * 在隊(duì)列的隊(duì)尾處插入元素
 * @param Q 隊(duì)列
 * @param e 插入元素值
 * @return 執(zhí)行狀態(tài)
 */
Status EnQueue(LinkQueue *Q, ElemType e) {
    // 給新節(jié)點(diǎn)分配空間
    QueuePtr s = (QueuePtr) malloc(sizeof(QNode));

    // 分配空間失敗,結(jié)束程序
    if (!s) {
        exit(OVERFLOW);
    }

    s->data = e; // 將值賦值給新節(jié)點(diǎn)
    s->next = NULL; // 新節(jié)點(diǎn)指向NULL
    Q->rear->next = s; // 隊(duì)尾指針的下一個(gè)元素指向新節(jié)點(diǎn)
    Q->rear = s; // 隊(duì)尾指針指向新節(jié)點(diǎn)(新節(jié)點(diǎn)成為隊(duì)尾指針的指向的節(jié)點(diǎn))
    return OK;
}

/**
 * 刪除隊(duì)頭元素
 * @param Q 隊(duì)列
 * @param e 存儲(chǔ)出隊(duì)元素的值
 * @return 執(zhí)行狀態(tài)
 */
Status DeQueue(LinkQueue *Q, ElemType *e) {
    QueuePtr p; // 用于指向被刪除節(jié)點(diǎn)

    // 隊(duì)列為空覆旭,出隊(duì)失敗
    if (Q->front == Q->rear) {
        return ERROR;
    }

    p = Q->front->next; // p指向隊(duì)列的第一個(gè)元素
    *e = p->data; // 將隊(duì)列頭節(jié)點(diǎn)的值賦值給元素e
    Q->front->next = p->next; // 頭指針的下一個(gè)節(jié)點(diǎn)指向下下個(gè)節(jié)點(diǎn)(跳過頭節(jié)點(diǎn))

    // 如果被刪除節(jié)點(diǎn)是隊(duì)尾指針指向的節(jié)點(diǎn)(刪除后隊(duì)列為空)
    if (Q->rear == p) {
        Q->rear = Q->front; // 隊(duì)尾指針指向隊(duì)頭指針
    }
    free(p); // 釋放隊(duì)頭節(jié)點(diǎn)
    return OK;
}

/**
 * 打印單個(gè)元素
 * @param e 元素值
 * @return 執(zhí)行狀態(tài)
 */
Status visit(ElemType e) {
    printf("%d ", e);
    return OK;
}

/**
 * 遍歷隊(duì)列中的元素
 * @param Q 隊(duì)列
 * @return 執(zhí)行狀態(tài)
 */
Status QueueTravel(LinkQueue Q) {
    QueuePtr p; // 用于遍歷隊(duì)列中的節(jié)點(diǎn)

    p = Q.front->next; // p指向頭節(jié)點(diǎn)

    printf("[ ");
    // 當(dāng)隊(duì)列中還有元素
    while (p) {
        visit(p->data); // 打印當(dāng)前節(jié)點(diǎn)的值
        p = p->next; // p移動(dòng)到隊(duì)列下一個(gè)位置
    }
    printf("]\n");
    return OK;
}

int main() {
    Status status; // 執(zhí)行狀態(tài)
    int j; // j用來遍歷
    ElemType e; // 元素值
    LinkQueue Q; // 隊(duì)列

    /*** 初始化隊(duì)列 ***/
    InitQueue(&Q); // 初始化隊(duì)列
    printf("初始化隊(duì)列后退子,隊(duì)列是否為空?%s\n", QueueEmpty(Q) == TRUE ? "是" : "否");

    /*** 向隊(duì)列中插入10個(gè)元素 ***/
    for (j = 1; j <=10; ++j) {
        EnQueue(&Q, j); // 將元素j插入隊(duì)列
    }
    printf("插入10個(gè)元素后隊(duì)列的值為:");
    QueueTravel(Q); // 遍歷隊(duì)列
    printf("隊(duì)列的長(zhǎng)度為:%d\n", QueueLength(Q)); // 獲取隊(duì)列長(zhǎng)度
    printf("插入10個(gè)元素后型将,隊(duì)列是否為空寂祥?%s\n", QueueEmpty(Q) == TRUE ? "是" : "否");

    /*** 刪除隊(duì)列中的五個(gè)元素,并打印對(duì)應(yīng)的值 ***/
    printf("開始刪除元素:\n");
    for (j = 0; j < 5; ++j) {
        DeQueue(&Q, &e); // 刪除隊(duì)頭元素七兜,將值存到e中
        printf("元素%d出隊(duì)\n", e);
    }
    printf("5個(gè)元素出隊(duì)后丸凭,隊(duì)列中的值為:");
    QueueTravel(Q); // 遍歷隊(duì)列
    printf("隊(duì)列的長(zhǎng)度為:%d\n", QueueLength(Q));  // 獲取隊(duì)列長(zhǎng)度

    /*** 獲取隊(duì)列頭元素的值 ***/
    status = GetHead(Q, &e); // 獲取隊(duì)列頭元素
    if (status) {
        printf("隊(duì)列頭元素為:%d\n", e);
    }

    /*** 清空隊(duì)列元素 ***/
    ClearQueue(&Q); // 清空隊(duì)列元素
    printf("清空隊(duì)列后,隊(duì)列是否為空:%s\n", QueueEmpty(Q) == TRUE ? "是" : "否");
    printf("隊(duì)列中的元素為:");
    QueueTravel(Q); // 遍歷元素
    return 0;
}
運(yùn)行結(jié)果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末腕铸,一起剝皮案震驚了整個(gè)濱河市惜犀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌狠裹,老刑警劉巖虽界,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異涛菠,居然都是意外死亡莉御,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門俗冻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颈将,“玉大人,你說我怎么就攤上這事言疗。” “怎么了颂砸?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵噪奄,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我人乓,道長(zhǎng)勤篮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任色罚,我火速辦了婚禮碰缔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘戳护。我一直安慰自己金抡,他們只是感情好瀑焦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著梗肝,像睡著了一般榛瓮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上巫击,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天禀晓,我揣著相機(jī)與錄音,去河邊找鬼坝锰。 笑死粹懒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的顷级。 我是一名探鬼主播凫乖,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼愕把!你這毒婦竟也來了拣凹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤恨豁,失蹤者是張志新(化名)和其女友劉穎嚣镜,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體橘蜜,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡菊匿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了计福。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跌捆。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖象颖,靈堂內(nèi)的尸體忽然破棺而出佩厚,到底是詐尸還是另有隱情,我是刑警寧澤说订,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布抄瓦,位于F島的核電站,受9級(jí)特大地震影響陶冷,放射性物質(zhì)發(fā)生泄漏钙姊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一埂伦、第九天 我趴在偏房一處隱蔽的房頂上張望煞额。 院中可真熱鬧,春花似錦、人聲如沸膊毁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽媚媒。三九已至嗜逻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缭召,已是汗流浹背栈顷。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嵌巷,地道東北人萄凤。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像搪哪,于是被迫代替她去往敵國(guó)和親靡努。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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