我本身实现了一个双向循环链表,发布在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 许可协议。转载请注明出处!
关注博主:若是您以为该文章对您有帮助,能够点击文章右下角推荐一下,您的支持将成为我最大的动力!