我本身實現了一個雙向循環鏈表,發佈在Github上。
叫QuickList,包含完整的鏈表模塊源碼和測試用例。遵循GPL V2.0協議。
你們能夠去github上獲取,若是以爲好用請幫我點個star,謝謝啦嘿嘿~
QuickList傳送門html
程序設計的基本法則之一是例程不該超過一頁,能夠經過把程序模塊化實現。每一個模塊是一個邏輯單位並執行某個特定的任務,它經過調用其餘模塊而使自己保持很小。優勢以下:node
概念:抽象數據類型ADT是一些操做的集合。這種操做的實現只在程序中編寫一次,而程序中任何其餘部分須要在該ADT上運行起鬨的一種操做時,能夠經過調用合適的函數來進行。若是要改變操做的細節,那麼只須要修改運行這些ADT操做的例程就很容易實現。git
連續存儲,訪問很快,插入刪除很慢,並且須要定義數組的大小,而這個大小一般要設的大一些浪費內存空間。因此簡單數組通常不用來實現表這種結構github
指針變量就是包含存儲另外某個數據地址的變量。所以,若是P被聲明爲指向一個結構的指針,那麼存儲在P中的值就被解釋爲主存中的一個位置,在該位置可以找到一個結構,該結構的一個域能夠經過P->FieldNme訪問。使用鏈表實現表,能夠在線性時間內完成PrintList/Find(L, Key)。FindKth(L, i)須要花費O(i)時間。實踐中這個界是保守的,由於調用FindKth經常以按i排序的方式進行。例如FindKth(L,2), FindKth(L,3)能夠經過對錶的一次掃描同時實現。刪除命令能夠經過一次free操做和一次指針的修改實現;插入命令能夠經過一次malloc操做和兩次指針修改實現算法
使用HEAD節點實現一些在表的前面實現插入和刪除操做。實現FindPrevious例程,來實現刪除節點的操做。編程
// 書上例程 int IsEmpty(List L) { return L->next == NULL; }
// 書上例程 int IsLast(Position P, List L) { return P->next == NULL; }
// 書上例程 Position Find(Element X, List L) { Position P; P = L->next; while (P != NULL && P->Element != X) { P = P->next; } return P; }
// 書上例程 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); } }
// 書上例程 Position FindPrevious(Element X, List L) { Position P; P = L; while (P->Next != NULL && P->next->Element != X) { P = P->next; } return P; }
// 書上例程 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中還有其餘函數,書上未實現,這裏我實現出來分享給你們。小程序
List MakeEmpty(List L) { Position P, tmp; P = L; while (P->next != NULL) { tmp = P->next; P->next = tmp->next; free(tmp); } return L; }
void DeleteList(List L) { MakeEmpty(L); free(L); }
Position Header(List L) { return L; }
Position First(List L) { return L->next; }
ElementType Retrieve(Position P) { return P->Element; }
須要在每一個節點上增長一個指向前驅節點的指針,增長了空間的需求,使得插入和刪除的空間開銷增長一倍,可是刪除速度加快了,由於前驅節點無需遍歷尋找api
最後一個節點的next指針指向第一個節點,若是有頭節點則指向頭節點。若是是雙向鏈表,則第一個節點的previous指針指向最後的節點數組
多項式ADT數據結構
//書上例程 typedef struct { int CoeffArray[MaxDegree + 1]; int HighPower; }
//書上例程 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"); }
多重表:節約空間,花費時間。也能夠在每一個節點中加入鏈表頭指針,花費空間,節約時間。如圖:
鏈表的遊標實現
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; } } }
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; }
int IsEmpty(List L) { return (CursorSpace[L].Next == 0); }
int IsLast(Position P, List L) { return (CursorSpace[P].Next == 0); }
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; }
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); } } }
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; }
節點定義
struct node; typedef struct node *PtrToNode; typede PtrToNode Stack; struct node { ElementType Element; PtrToNode Next; }
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; }
void MakeEmpty(Stack s) { PtrToNode p = NULL, tmp = NULL; p = s->Next; while (p != NULL) { tmp = p->Next; free(p); p = tmp; } }
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; }
void Pop(Stack s) { if (s == NULL || s->Next == NULL) { return NULL; } PtrToNode tmp = NULL; tmp = s->Next; s->Next = tmp->Next; free(tmp); }
ElementType Top(Stack s) { return s->Next.Element; }
int IsEmpty(Stack s) { if (s == NULL) { return -1; } return (s->Next == NULL); }
一個影響棧的執行效率的問題是錯誤檢測。除非在錯誤處理極其重要的場合(如在操做系統中),慣用手法是在棧例程中省去錯誤檢測。當編寫程序時,忽略錯誤檢測通常是不妥的,應該隨時編寫錯誤檢測的代碼,若是它們冗長,當它們確實耗費太多時間時,能夠將它們去掉。
struct StackRecord; typedef struct StackRecord *Stack; #define EmptyTOS (-1) #define MinStackSize (5) struct StackRecord { int Capacity; int TopOfStack; ElementType *Array; }
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; }
void DisposeStack(Stack s) { if (s->Array != NULL) { free(s->Array); s->Array = NULL; } if (s != NULL) { free(s); } }
int IsEmpty(Stack s) { return (s->TopOfStack == EmptyTOS); }
void MakeEmtpy(Stack s) { memset(s->Array, 0, sizeof(ElementType) * s->Capacity); s->TopOfStack = EmptyTOS; }
int IsFull(Stack s) { return (s->TopOfStack + 1 == s->Capacity); }
void Push(Stack s, ElementType X) { if (IsFull(s)) { printf("stack s is full\n"); return; } s->array[++s->TopOfStack] = X; }
ElementType TopAndPop(Stack s) { if (s->TopOfStack == EmptyTOS) { return EmptyTOS; } return s->array[s->TopOfStack--]; }
void Pop(Stack s) { if (IsEmpty(s)) { printf("stack s is empty\n"); } s->TopOfStack--; }
ElementType Top(Stack s) { return s->Array[s->TopOfStack]; }
平衡符號
#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"); } }
#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); }
#define CAPACITY 10 struct QueueRecord { int Capacity; int Front; int Rear; int Size; ElementType *Array; } typedef struct QueueRecord *Queue;
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; }
void DisposeQueue(Queue Q) { if (Q == NULL) { return; } if (Q->Array != NULL) { free(Q->Array); } free(Q); }
int IsEmpty(Queue Q) { if (Q == NULL) { return -1; } return (Q->Size == 0); }
int IsFull(Queue Q) { if (Q == NULL) { return -1; } return (Q->Size == Q->Capicity); }
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; }
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; }
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
int IsEmpty(QueueHead Q) { if (Q == NULL) { return -1; } return (Q->Next == Q); }
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); }
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; }
int DisposeQueue(QueueHead Q) { if (Q == NULL) { return -1; } MakeEmpty(Q); free(Q); return 0; }
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; }
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; }
ElementType Front(QueueHead Q) { if (Q == NULL) { return EMPTY; } if (IsEmpty(Q)) { return EMPTY; } return Q->Next->Element; }
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; }
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; }
排隊論:問題取決於用戶加入隊列的頻率,以及一旦用戶獲得服務時處理服務的時間。
遞歸很是強大,但它並非徹底隨意的操做;遞歸的誤用和亂用可能致使程序崩潰。
本文做者: CrazyCatJack
本文連接: https://www.cnblogs.com/CrazyCatJack/p/13321878.html
版權聲明:本博客全部文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!
關注博主:若是您以爲該文章對您有幫助,能夠點擊文章右下角推薦一下,您的支持將成爲我最大的動力!