Hi, all!我自己實現了一個雙向循環鏈表,發布在Github上。
叫QuickList,包含完整的鏈表模塊源碼和測試用例。遵循GPL V2.0協議。
大家可以去github上獲取,如果覺得好用請幫我點個star,謝謝啦嘿嘿~
QuickList傳送門
3.1 抽象數據類型
程序設計的基本法則之一是例程不應超過一頁,可以通過把程序模塊化實現。每個模塊是一個邏輯單位並執行某個特定的任務,它通過調用其他模塊而使本身保持很小。優點如下:
- 調試小程序比調試大程序容易得多
- 多個人同時對一個模塊式程序編程要更容易
- 一個好的模塊化程序把某些依賴關系只局限在一個歷程中,這樣修改起來會更容易
- 全局變量及其副作用是有害的觀念也正是出於模塊化是有益的想法
概念:抽象數據類型ADT是一些操作的集合。這種操作的實現只在程序中編寫一次,而程序中任何其他部分需要在該ADT上運行起哄的一種操作時,可以通過調用合適的函數來進行。如果要改變操作的細節,那么只需要修改運行這些ADT操作的例程就很容易實現。
3.2 表ADT
- 我們將處理一般的形如 A1, A2, A3, ... , AN的表,我們說這個表的大小是N,我們稱大小為0的表為空表。對於除空表外的任何表,我們說Ai+1后繼Ai(i < N),並稱Ai-1前驅Ai(i > 1)。表中的第一個元素是A1,而最后一個元素是AN。我們將不定義A1的前驅元,也不定義AN的后繼元。元素Ai在表中的位置為i
- 與這些“定義”相關的是我們要在表ADT上進行的操作的集合。PrintList/MakeEmpty/Find/Insert/Delete/FindKth/Next/Previous等
3.2.1 表的簡單數組實現
連續存儲,訪問很快,插入刪除很慢,而且需要定義數組的大小,而這個大小通常要設的大一些浪費內存空間。所以簡單數組一般不用來實現表這種結構
3.2.2 鏈表
指針變量就是包含存儲另外某個數據地址的變量。因此,如果P被聲明為指向一個結構的指針,那么存儲在P中的值就被解釋為主存中的一個位置,在該位置能夠找到一個結構,該結構的一個域可以通過P->FieldNme訪問。使用鏈表實現表,可以在線性時間內完成PrintList/Find(L, Key)。FindKth(L, i)需要花費O(i)時間。實踐中這個界是保守的,因為調用FindKth常常以按i排序的方式進行。例如FindKth(L,2), FindKth(L,3)可以通過對表的一次掃描同時實現。刪除命令可以通過一次free操作和一次指針的修改實現;插入命令可以通過一次malloc操作和兩次指針修改實現
3.2.3 程序設計細節
使用HEAD節點實現一些在表的前面實現插入和刪除操作。實現FindPrevious例程,來實現刪除節點的操作。
- IsEmpty
// 書上例程
int
IsEmpty(List L)
{
return L->next == NULL;
}
- IsLast
// 書上例程
int
IsLast(Position P, List L)
{
return P->next == NULL;
}
- Find
// 書上例程
Position
Find(Element X, List L)
{
Position P;
P = L->next;
while (P != NULL && P->Element != X) {
P = P->next;
}
return P;
}
- Delete
// 書上例程
void
Delete(Element X, List L)
{
Position P, TmpCell;
P = FindPrevious(X, L);
if (!IsLast(P, L)) {
TmpCell = P->next;
P->next = TmpCell->next;
free(TmpCell);
}
}
- FindPrevious
// 書上例程
Position
FindPrevious(Element X, List L)
{
Position P;
P = L;
while (P->Next != NULL && P->next->Element != X) {
P = P->next;
}
return P;
}
- Insert
// 書上例程
void
Insert(Element X, List L, Postion P)
{
Position new = malloc(sizeof(Position));
if (new == NULL) {
printf("malloc failed!\n");
}
memset(new, 0, sizeof(Position));
new->Element = X;
new->next = P->next;
P->next = new;
}
ADT中還有其他函數,書上未實現,這里我實現出來分享給大家。
- MakeEmpty
List
MakeEmpty(List L)
{
Position P, tmp;
P = L;
while (P->next != NULL) {
tmp = P->next;
P->next = tmp->next;
free(tmp);
}
return L;
}
- DeleteList
void
DeleteList(List L)
{
MakeEmpty(L);
free(L);
}
- Header
Position
Header(List L)
{
return L;
}
- First
Position
First(List L)
{
return L->next;
}
- Retrieve
ElementType
Retrieve(Position P)
{
return P->Element;
}
3.2.4 常見的錯誤
- 初始化變量失敗或參數是否超出規定范圍的。應該增加初始化檢查或者參數檢查,再進行相關操作
- 聲明指向一個結構的指針,並不創建該結構。使用malloc庫函數。它創建一個新的結構並返回指向該結構的指針。如果想讓指針變量沿着表前進,則沒必要創建新的結構。
- free(P)的結果是:P正在指向的地址沒變,但是該地址處的數據此時已經無定義了
- 如果從未對一個鏈表進行過刪除操作,那么調用malloc的次數應該等於表的大小,若有表頭則再加1
- 刪除節點,需要一個臨時變量。因為節點被free之后,無法訪問到原指針指向的地址
- malloc(sizeof(PtrToNode))只是給指針分配一個空間,並不給結構體分配足夠的空間
3.2.5 雙鏈表
需要在每個節點上增加一個指向前驅節點的指針,增加了空間的需求,使得插入和刪除的空間開銷增加一倍,但是刪除速度加快了,因為前驅節點無需遍歷尋找
3.2.6 循環鏈表
最后一個節點的next指針指向第一個節點,如果有頭節點則指向頭節點。如果是雙向鏈表,則第一個節點的previous指針指向最后的節點
3.2.7 例子
多項式ADT
- 多項式結構體定義
//書上例程
typedef struct {
int CoeffArray[MaxDegree + 1];
int HighPower;
}
- 初始化多項式為0
//書上例程
void
ZeroPolynomial(Polynomial Poly)
{
int i;
for (i = 0; i <= MaxDegree; i++) {
Poly.CoeffArray[i] = 0;
}
Poly.HighPower = 0;
}
- 多項式相加
//書上例程,時間復雜度O(N)
void
AddPolynomial(const Polynomial Poly1, const Polynomial Poly2, Polynomial PolySum)
{
int i;
ZeroPolynomial(PolySum);
PolySum->HighPower = Max(Poly1->HighPower, Poly2->HighPower);
for (i = 0; i < PolySum->HighPower; i++) {
PolySum->CoeffArray[i] = Poly1->CoeffArray[i] + Poly2->CoeffArray[i];
}
}
- 多項式相乘
//書上例程,時間復雜度O(N^2)
void
MultPolynomial(const Polynomial Poly1, const Polynomial Poly2, Polynomial PolyProd)
{
int i, j;
ZeroPolynomial(PolyProd);
PolyProd->HighPower = Poly1->HighPower + Poly2->HighPower;
if (PolyProd->HighPower > MaxDegree) {
printf("Exceeded array size");
} else {
for (i = 0; i < Poly1->HighPower; i++) {
for (j = 0; j < Poly2->HighPower; j++) {
PolyProd->CoeffArray[i + j] += Poly1->CoeffArray[i] * Poly2->CoeffArray[j];
}
}
}
}
另一種方法:單鏈表。多項式的每一項含在一個節點中,並且這些節點以次數遞減的順序排序。
- 節點結構體定義
//書上例程
struct Node {
int Cofficient;
int Exponent;
PtrToNode Next;
}
typedef struct Node *PtrToNode;
typedef PtrToNode Polynomial;
- 創建並初始化節點
//自己寫的
Polynomial
CreatePolynomial()
{
Polynomial tmp;
tmp = (Polynomial)malloc(sizeof(struct Node));
memset(tmp, 0, sizeof(struct Node));
return tmp;
}
- 銷毀並釋放節點
//自己寫的
void
DestroyPolynomial(Polynomial P)
{
free(P);
}
- 多項式相加
//自己寫的。時間復雜度O(N^2)
void
AddPolynomial(const Polynomial Poly1, const Polynomial Poly2, Polynomial PolySum)
{
int i, j;
Polynomial P1, P2, Psum, Ptmp;
Psum = PolySum;
for (P1 = Poly1->next; P1 != NULL; P1 = P1->next) {
for (P2 = Poly2->next; P2 != NULL; P2 = P2->next) {
if (P1->Exponent == P2->Exponent) {
break;
}
}
Ptmp = CreatePolynomial();
Ptmp->Exponent = P1->Exponent;
if (P2 == NULL) {
Ptmp->Cofficient = P1->Cofficient;
} else {
Ptmp->Cofficient = P1->Cofficient + P2->Cofficient;
}
Psum->next = Ptmp;
Ptmp->next = NULL;
Psum = Psum->next;
}
}
- 多項式相乘
//自己寫的。時間復雜度O(N^3)
void
MultPolynomial(const Polynomial Poly1, const Polynomial Poly2, Polynomial PolyProd)
{
int i, j, exponentTmp;
Polynomial P1, P2, Prod, Ptmp;
Prod = PolyProd->next;
for (P1 = Poly1->next; P1 != NULL; P1 = P1->next) {
for (P2 = Poly2->next; P2 != NULL; P2 = P2->next) {
exponentTmp = P1->Exponent + P2->Exponent;
while (Prod != NULL) {
if (Prod->Exponent == exponentTmp) {
Prod->Cofficient += P1->Cofficient * P2->Cofficient;
break;
}
Prod = Prod->next;
}
if (Prod == NULL) {
Ptmp = CreatePolynomial();
Ptmp->Exponent = exponentTmp;
Ptmp->Cofficient = P1->Cofficient * P2->Cofficient;
Prod = PolyProd->next;
PolyProd->next = Ptmp;
Ptmp->next = Prod;
}
}
}
}
桶式排序
// 自己寫的,時間復雜度O(N)
void
sortBucket(int *array, int num, int maxSize)
{
int CountArraySize = maxSize + 1;
int *Count = (int *)malloc(CountArraySize * sizeof(int));
memset(Count, 0, CountArraySize * sizeof(int));
int inputCnt;
for (inputCnt = 0; inputCnt < num; inputCnt++) {
Count[array[inputCnt]] = array[inputCnt];
}
for (inputCnt = 1; inputCnt < CountArraySize; inputCnt++) {
if (Count[inputCnt] != 0) {
printf("%d", Count[inputCnt]);
}
}
}
基數排序,我自己實現了並上傳到了Github上,大家可以獲得源碼。
bucketSort2
// SPDX-License-Identifier: GPL-2.0-only
/*
* bucketSort2.c
*
* Copyright (C) 2020 xuri
*/
/*
* This file show how bucket sort running, it based on QuickList module
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "QuickList.h"
#define ARRAY_NUM 10
#define BUCKET_NUM 10 //10 buckets
#define NUMBER_RANGE 3 // 0 - 999
void bucketSort2(int *inputArray, int num)
{
int divisor = 1;
int cnt;
int *recvdata;
int times = 0;
QuickListNode_T *tmp = NULL, *tmp2 = NULL;
QuickListNode_T *qlArray[BUCKET_NUM];
/* initialize the qlArray */
memset(qlArray, 0, BUCKET_NUM);
for (cnt = 0; cnt < BUCKET_NUM; cnt++) {
qlArray[cnt] = QuickListCreateList();
}
/* first time input array and create listnode add to qlArray */
for (cnt = 0; cnt < num; cnt++) {
tmp = QuickListCreateNode(&inputArray[cnt]);
QuickListAddNodetoTail(qlArray[(inputArray[cnt] / divisor % 10)], tmp);
}
printf("after first time\n");
/* finish bucket sort */
while (times < NUMBER_RANGE - 1) {
divisor *= 10;
for (cnt = 0; cnt < BUCKET_NUM; cnt++) {
tmp = NULL;
tmp2 = NULL;
QuickList_for_each_entry_safe(qlArray[cnt], tmp, tmp2) {
recvdata = QuickList_entry(int, tmp);
if ((*recvdata / divisor % 10) != cnt) {
QuickListDetachNode(qlArray[cnt], tmp);
QuickListAddNodetoTail(qlArray[(*recvdata / divisor % 10)], tmp);
}
}
}
times++;
}
/* print array after bucket sort */
printf("Start print array after bucket sort:\n");
for (cnt = 0; cnt < BUCKET_NUM; cnt++) {
QuickList_for_each_entry(qlArray[cnt], tmp) {
recvdata = QuickList_entry(int, tmp);
printf("%d ", *recvdata);
}
}
printf("\n");
}
多重表:節約空間,花費時間。也可以在每個節點中加入鏈表頭指針,花費空間,節約時間。如圖:
鏈表的游標實現
- InitializeCursorSpace
struct node
{
ElementType Element;
Position Next;
}
typedef int PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;
struct Node CursorSpace[SpaceSize];
void InitializeCursorSpace(void)
{
int cnt;
for (cnt = 0; cnt < SpaceSize; cnt++) {
CursorSpace[cnt].Element = 0;
if (cnt + 1 >= SpaceSize) {
CursorSpace[cnt].Next = 0;
} else {
CursorSpace[cnt].Next = cnt + 1;
}
}
}
- CursorAlloc & CursorFree
static Position
CursorAlloc()
{
Position P;
P = CursorSpace[0].Next;
CursorSpace[0].Next = CursorSpace[P].Next;
return P;
}
static void
CursorFree(Position X)
{
CursorSpace[X].Next = CursorSpace[0].Next;
CursorSpace[0].Next = X;
}
- IsEmpty
int
IsEmpty(List L)
{
return (CursorSpace[L].Next == 0);
}
- IsLast
int
IsLast(Position P, List L)
{
return (CursorSpace[P].Next == 0);
}
- Find
Position
Find(ElementType X, List L)
{
Position tmp;
for(tmp = CursorSpace[L].Next; tmp != 0; tmp = CursorSpace[tmp].Next) {
if (CursorSpace[tmp].Element == X) {
break;
}
}
return tmp;
}
- Delete
void
Delete(ElementType X, List L)
{
Position tmp, tmpNext;
for (tmp = L; CursorSpace[tmp].Next != 0; tmp = CursorSpace[tmp].Next) {
tmpNext = CursorSpace[tmp].Next;
if (CursorSpace[tmpNext].Element == X) {
CursorSpace[tmp].Next = CursorSpace[tmpNext].Next;
CursorFree(tmpNext);
}
}
}
- Insert
void
Insert(ElementType X, List L)
{
Position P;
P = CursorAlloc();
if (P == 0) {
printf("run out of memory\n");
return;
}
CursorSpace[P].Element = X;
CursorSpace[P].Next = CursorSpace[L].Next;
CursorSpace[L].Next = P;
}
3.3 棧ADT
1) 單鏈表實現
節點定義
struct node;
typedef struct node *PtrToNode;
typede PtrToNode Stack;
struct node {
ElementType Element;
PtrToNode Next;
}
- CreateStack
Stack
CreateStack(void)
{
Stack s = NULL;
s = (Stack)malloc(sizeof(struct node));
if (s == NULL) {
printf("stack malloc failed\n");
return s;
}
memset(s, 0, sizeof(struct node));
s->Next = NULL;
return s;
}
- MakeEmpty
void
MakeEmpty(Stack s)
{
PtrToNode p = NULL, tmp = NULL;
p = s->Next;
while (p != NULL) {
tmp = p->Next;
free(p);
p = tmp;
}
}
- Push
int
Push(ElementType X, Stack s)
{
PtrToNode tmp = NULL;
tmp = (PtrToNode)malloc(sizeof(struct node));
if (tmp == NULL) {
return -1;
}
memset(tmp, 0, sizeof(struct node));
tmp->Element = X;
tmp->Next = s->Next;
s->Next = tmp;
return 0;
}
- Pop
void
Pop(Stack s)
{
if (s == NULL || s->Next == NULL) {
return NULL;
}
PtrToNode tmp = NULL;
tmp = s->Next;
s->Next = tmp->Next;
free(tmp);
}
- Top
ElementType
Top(Stack s)
{
return s->Next.Element;
}
- IsEmtpy
int
IsEmpty(Stack s)
{
if (s == NULL) {
return -1;
}
return (s->Next == NULL);
}
2) 棧的數組實現
一個影響棧的執行效率的問題是錯誤檢測。除非在錯誤處理極其重要的場合(如在操作系統中),慣用手法是在棧例程中省去錯誤檢測。當編寫程序時,忽略錯誤檢測一般是不妥的,應該隨時編寫錯誤檢測的代碼,如果它們冗長,當它們確實耗費太多時間時,可以將它們去掉。
- 棧定義
struct StackRecord;
typedef struct StackRecord *Stack;
#define EmptyTOS (-1)
#define MinStackSize (5)
struct StackRecord
{
int Capacity;
int TopOfStack;
ElementType *Array;
}
- CreateStack
Stack
CreateStack(int MaxElement)
{
if (MaxElement < MinStackSize) {
return NULL;
}
Stack s = NULL;
s = (Stack)malloc(sizeof(struct StackRecord));
if (s == NULL) {
return NULL;
}
memset(s, 0, sizeof(struct StackRecord));
s->Capacity = MaxElement;
s->TopOfStack = EmptyTOS;
s->Array = (ElementType *)malloc(sizeof(ElementType) * MaxElement);
if (s->Array == NULL) {
free(s);
return NULL;
}
memset(s->Array, 0, sizeof(ElementType) * MaxElement);
return s;
}
- DisposeStack
void
DisposeStack(Stack s)
{
if (s->Array != NULL) {
free(s->Array);
s->Array = NULL;
}
if (s != NULL) {
free(s);
}
}
- IsEmpty
int
IsEmpty(Stack s)
{
return (s->TopOfStack == EmptyTOS);
}
- MakeEmpty
void
MakeEmtpy(Stack s)
{
memset(s->Array, 0, sizeof(ElementType) * s->Capacity);
s->TopOfStack = EmptyTOS;
}
- IsFull
int
IsFull(Stack s)
{
return (s->TopOfStack + 1 == s->Capacity);
}
- Push
void
Push(Stack s, ElementType X)
{
if (IsFull(s)) {
printf("stack s is full\n");
return;
}
s->array[++s->TopOfStack] = X;
}
- TopAndPop
ElementType
TopAndPop(Stack s)
{
if (s->TopOfStack == EmptyTOS) {
return EmptyTOS;
}
return s->array[s->TopOfStack--];
}
- Pop
void
Pop(Stack s)
{
if (IsEmpty(s)) {
printf("stack s is empty\n");
}
s->TopOfStack--;
}
- Top
ElementType
Top(Stack s)
{
return s->Array[s->TopOfStack];
}
3) 應用
平衡符號
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stackADT.h"
#define BRACKET_TYPE 3
#define TEST_STR "(abcd}[ef])"
char bracketOpen[BRACKET_TYPE] = {'{', '(', '['};
char bracketClose[BRACKET_TYPE] = {'}', ')', ']'};
int symbolCheck(char *inputStr)
{
int strLen = strlen(inputStr);
int cnt, cnt2;
char tmp;
int ret = -1;
Stack s = CreateStack();
if (s == NULL) {
return ret;
}
for (cnt = 0; cnt < strLen; cnt++) {
for (cnt2 = 0; cnt2 < BRACKET_TYPE; cnt2++) {
if (inputStr[cnt] == bracketOpen[cnt2]) {
Push(inputStr[cnt], s);
}
if (inputStr[cnt] == bracketClose[cnt2]) {
tmp = Top(s);
if (tmp != bracketOpen[cnt2]) {
goto __exit;
}
Pop(s);
}
}
}
if (!IsEmpty(s)) {
goto __exit;
}
ret = 0;
__exit:
DistroyStack(s);
return ret;
}
void main()
{
char *p = TEST_STR;
if (0 == symbolCheck(p)) {
printf("check success\n");
} else {
printf("check fail\n");
}
}
- 后綴表達式:時間復雜度O(N),因為對輸入中每個元素的處理都是由一些棧操作組成並花費常熟時間,該算法的計算是非常簡單的。當一個表達式以后綴記號給出時,沒有必要知道任何優先規則,這是一個明顯的優點
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stackADT.h"
#define OPERATOR_TYPE 4
char Operator[OPERATOR_TYPE] = {'+', '-', '*', '/'};
char *Expression = "12+3*85-/";
void suffixExpression(char *inputStr)
{
int cnt, cnt2;
int operateNum1, operateNum2;
Stack s = CreateStack();
for (cnt = 0; inputStr[cnt] != '\0'; cnt++) {
if ((inputStr[cnt] >= '0') && (inputStr[cnt] <= '9')) {
printf("Push %d\n", (inputStr[cnt] - '0'));
Push((inputStr[cnt] - '0'), s);
}
for (cnt2 = 0; cnt2 < OPERATOR_TYPE; cnt2++) {
if (inputStr[cnt] == Operator[cnt2]) {
operateNum2 = Top(s);
Pop(s);
operateNum1 = Top(s);
Pop(s);
printf("operator=%c, num1=%d, num2=%d\n", Operator[cnt2], operateNum1, operateNum2);
switch (cnt2) {
case 0: {
Push((operateNum1 + operateNum2), s);
printf("Push %d\n", operateNum1 + operateNum2);
break;
}
case 1: {
Push((operateNum1 - operateNum2), s);
printf("Push %d\n", operateNum1 - operateNum2);
break;
}
case 2: {
Push((operateNum1 * operateNum2), s);
printf("Push %d\n", operateNum1 * operateNum2);
break;
}
case 3: {
Push((operateNum1 / operateNum2), s);
printf("Push %d\n", operateNum1 / operateNum2);
break;
}
default:
break;
}
}
}
}
operateNum1 = Top(s);
Pop(s);
DistroyStack(s);
printf("result=%d\n", operateNum1);
}
void main()
{
suffixExpression(Expression);
}
- 中綴到后綴的轉換: 當讀到一個操作數的時候,立即把它放到輸出中,操作符不立即輸出,從而必須先存在某個地方。正確的做法是將已經見到過的操作符放到棧中,而不是放到輸出中。當遇到左圓括號時我們也要將其推入棧中,從一個空棧開始計算。如果見到一個右括號,那么就將棧元素彈出,將彈出的符號寫出直到我們遇到一個左括號,但是這個左括號和右括號只是彈出,並不輸出。如果見到其他任何操作符號,那么就從棧中彈出棧元素,直到發現優先級更低的元素則不彈出,將讀取到的操作符入棧(若優先級相同則出棧)。有一個例外,除非是在處理一個)的時候,否則我們絕不從棧中移走(。因此,當從棧彈出元素的工作完成后,再將操作符壓入棧中。最后,如果讀到輸入的末尾,我們將棧元素彈出直到該棧變成空棧。將符號寫道輸出中。
- 函數調用: 函數的嵌套調用過程中,主調例程的所有局部變量和返回地址要被保存起來(入棧),在被調例程結束后進行恢復(出棧)。因此全部工作均可由一個棧來完成。當前環境是由棧頂描述的。因此,一條返回語句就可給出前面的環境。實際計算機中的棧,常常時從內存分區的高端向下增長。而在許多系統中是不檢測棧溢出的,但是用盡棧空間的情況總是可能發生的。棧溢出的后果是嚴重的:程序崩潰,數據錯誤。在正常情況下不應該越出棧空間,發生這種情況通常是由失控遞歸的指向引起的(忘記基准情形),也有可能是某些表面上正確的程序,但是遞歸了N次(數量巨大),導致棧溢出。例如尾遞歸。
- 尾遞歸完全可由goto語句改造出來。例如可以goto到頂部。遞歸總能夠被徹底除去(編譯器是在轉變成匯編語言時完成的)雖然非遞歸程序一般說來確實比等價的遞歸程序要快,但是代價時使得程序的清晰性變得不足
3.4 隊列
數組實現
- 節點定義
#define CAPACITY 10
struct QueueRecord {
int Capacity;
int Front;
int Rear;
int Size;
ElementType *Array;
}
typedef struct QueueRecord *Queue;
- CreateQueue
Queue
CreateQueue(int MaxElements)
{
if (MaxElements <= 0) {
return NULL;
}
Queue q = NULL;
q = (Queue)malloc(sizeofstruct QueueRecord(struct QueueRecord));
if (q == NULL) {
printf("queue malloc failed\n");
return NULL;
}
memset(q, 0, sizeof(struct QueueRecord));
q->Capacity = CAPACITY;
q->Front = 1;
q->Rear = 0;
q->Size = 0;
q->Array = (ElementType *)malloc(sizeof(ElementType) * CAPACITY);
if (q->Array == NULL) {
return NULL;
}
memset(q->Array, 0, sizeof(ElementType) * CAPACITY);
return q;
}
- DisposeQueue
void
DisposeQueue(Queue Q)
{
if (Q == NULL) {
return;
}
if (Q->Array != NULL) {
free(Q->Array);
}
free(Q);
}
- IsEmpty
int
IsEmpty(Queue Q)
{
if (Q == NULL) {
return -1;
}
return (Q->Size == 0);
}
- IsFull
int
IsFull(Queue Q)
{
if (Q == NULL) {
return -1;
}
return (Q->Size == Q->Capicity);
}
- Enqueue
int
Enqueue(Queue Q, Element X)
{
if (Q == NULL) {
return -1;
}
if (IsFull(Q)) {
printf("Queue Q is full\n");
return -1;
}
if (++(Q->Rear) >= Q->Capicity) {
Q->Rear -= Q->Capicity;
}
Q->Array[Q->Rear] = X;
Q->Size++;
return 0;
}
- Dequeue
int
Dequeue(Queue Q)
{
if (Q == NULL) {
return -1;
}
if (IsEmpty(Q)) {
printf("Queue Q is empty\n");
return -1;
}
if (++(Q->Front) >= Q->Capicity) {
Q->Front -= Q->Capicity;
}
Q->Size--;
return 0;
}
- FrontAndDequeue
ElementType
FrontAndDequeue(Queue Q)
{
if (Q == NULL) {
return -1;
}
if (IsEmpty(Q)) {
printf("Queue Q is empty\n");
return -1;
}
ElementType ret = Q->Array[Q->Front];
if (++(Q->Front) >= Q->Capicity) {
Q->Front -= Q->Capicity;
}
Q->Size--;
return ret;
}
鏈表實現
- 節點定義
typedef struct Queue {
ElementType Element;
struct Queue *Pre;
struct Queue *Next;
} Queue_T;
typedef Queue_T *QueuePtr
typedef QueuePtr QueueHead
#define MaxSize 10
#define EMPTY -1
- IsEmpty
int
IsEmpty(QueueHead Q)
{
if (Q == NULL) {
return -1;
}
return (Q->Next == Q);
}
- IsFull
int
IsFull(QueueHead Q)
{
if (Q == NULL) {
return -1;
}
int queueCnt = 0;
QueuePtr tmp = NULL;
tmp = Q->Next;
while (tmp != Q) {
queueCnt++;
tmp = tmp->Next;
}
return (queueCnt == MaxSize);
}
- CreateQueue
QueueHead
CreateQueue()
{
QueueHead Q = NULL;
Q = (QueuePtr)malloc(sizeof(struct Queue));
if (Q == NULL) {
return NULL;
}
memset(Q, 0, sizeof(struct Queue));
Q->Next = Q;
Q->Pre = Q;
return Q;
}
- DisposeQueue
int
DisposeQueue(QueueHead Q)
{
if (Q == NULL) {
return -1;
}
MakeEmpty(Q);
free(Q);
return 0;
}
- MakeEmpty
int
MakeEmpty(QueueHead Q)
{
if (Q == NULL) {
return -1;
}
QueueHead tmp = NULL, tmpNext = NULL;
tmp = Q->Next;
while (tmp != Q) {
if (tmp) {
tmpNext = tmp->Next;
free(tmp);
tmp = tmpNext;
}
}
return 0;
}
- Enqueue
int
Enqueue(QueueHead Q, ElementType Element)
{
if (Q == NULL) {
return -1;
}
if (IsFull(Q)) {
return -1;
}
QueuePtr qAdd = NULL;
qAdd = (QueuePtr)malloc(sizeof(struct Queue));
if (qAdd == NULL) {
return -1;
}
memset(qAdd, 0, sizeof(struct Queue));
qAdd->Element = Element;
qAdd->Pre = Q->Pre;
qAdd->Next = Q;
Q->Pre->Next = qAdd;
Q->Pre = qAdd;
return 0;
}
- Front
ElementType
Front(QueueHead Q)
{
if (Q == NULL) {
return EMPTY;
}
if (IsEmpty(Q)) {
return EMPTY;
}
return Q->Next->Element;
}
- Dequeue
int
Dequeue(QueueHead Q)
{
if (Q == NULL) {
return -1;
}
if (IsEmpty(Q)) {
return -1;
}
QueuePtr tmp = NULL;
tmp = Q->Next;
Q->Next = tmp->Next;
tmp->Next->Pre = Q;
if (tmp != NULL) {
free(tmp);
}
return 0;
}
- FrontAndDequeue
ElementType
FrontAndDequeue(QueueHead Q)
{
if (Q == NULL) {
return EMPTY;
}
if (IsEmpty(Q)) {
return EMPTY;
}
ElementType ret;
QueuePtr tmp = NULL;
tmp = Q->Next;
ret = tmp->Element;
Q->Next = tmp->Next;
tmp->Next->Pre = Q;
if (tmp != NULL) {
free(tmp);
}
return ret;
}
3.4.3 隊列的應用
排隊論:問題取決於用戶加入隊列的頻率,以及一旦用戶得到服務時處理服務的時間。
遞歸非常強大,但它並不是完全隨意的操作;遞歸的誤用和亂用可能導致程序崩潰。
參考文獻
- Mark Allen Weiss.數據結構與算法分析[M].America, 2007
本文作者: CrazyCatJack
本文鏈接: https://www.cnblogs.com/CrazyCatJack/p/13321878.html
版權聲明:本博客所有文章除特別聲明外,均采用 BY-NC-SA 許可協議。轉載請注明出處!
關注博主:如果您覺得該文章對您有幫助,可以點擊文章右下角推薦一下,您的支持將成為我最大的動力!