C語言資料結構-二叉樹、哈夫曼、佇列小練習
阿新 • • 發佈:2018-11-16
原始碼地址 GitHub:https://github.com/GYT0313/C-DataStructure
1. 二叉樹
要求:
- 掌握二叉樹的二叉連結串列的建立方法;
- 掌握二叉樹的3種遍歷遞迴演算法;
- 掌握二叉樹的3種遍歷的非遞迴演算法。
程式碼:
#include <stdio.h> #include <stdlib.h> #define M 100 typedef struct node { char data; struct node *lchild, *rchild; }BTNode; /* * 建立二叉樹: * *建立次序為從左到右 *遇到 # 時返回上一層,標誌位變為 2 也就是該節點的右子樹 *右子樹為 # 時出棧該節點,並訪問父節點的右子樹 * */ BTNode *createBiTree( char *str ) { BTNode *s[M]; /* 棧 */ BTNode *b=NULL, *p; /* b:指向根節點, p:直接新創節點 */ int top=-1, i=0, flag=1; while ( str[i] != '\0') { if ( str[i] != '#' ) { p = (BTNode *)malloc(sizeof(BTNode)); p->data = str[i]; p->lchild = p->rchild = NULL; if ( b == NULL ) /* b 指向根節點 */ b = p; else { switch ( flag ) { case 1: /* 左子樹 */ s[top]->lchild = p; break; case 2: /* 右子樹 */ s[top]->rchild = p; top--; /* 出棧 */ break; } } s[++top] = p; /* 入棧 */ flag = 1; } else { flag = 2; if ( str[i-1] == '#' ) /* 該節點沒有左右子樹,則出棧 */ top--; } i++; } return b; } ///////////////// 遞迴遍歷 //////////////////////// /* 先序遞迴演算法 */ void PreOrder1( BTNode *b ) { if ( b == NULL ) return ; else { printf(" %c", b->data); PreOrder1( b->lchild ); PreOrder1( b->rchild ); } } /* 中序遞迴演算法 */ void InOrder1( BTNode *b ) { if ( b == NULL ) return ; else { InOrder1( b->lchild ); printf(" %c", b->data); InOrder1( b->rchild ); } } /* 後序遞迴演算法 */ void PostOrder1( BTNode *b ) { if ( b == NULL ) return ; else { PostOrder1( b->lchild ); PostOrder1( b->rchild ); printf(" %c", b->data); } } ///////////////// 非遞迴遍歷 //////////////////////// ///////////////// 非遞迴藉助於棧來實現 /* 先序非遞迴演算法 */ /* *先序遍歷從左到右,當p指向空時,該節點出棧,並且 p 指向該節點的右子樹 *若右子樹也為空,則出棧該節點的父節點,並且 p 指向父節點的右子樹 * */ void PreOrder( BTNode *b ) { BTNode *s[M], *p = b; int top=-1; while ( p != NULL || top != -1 ) /* p不為空,棧不為空 */ { if ( p != NULL ) /* 訪問左子樹 */ { printf(" %c", p->data); s[++top] = p; /* 入棧 */ p = p->lchild; } else /* 訪問右子樹 */ { p = s[top--]; /* p 指向棧頂,並且出棧*/ p = p->rchild; } } } /* 中序非遞迴演算法 */ void InOrder( BTNode *b ) { BTNode *s[M], *p = b; int top=-1; while ( p != NULL || top != -1 ) { if ( p != NULL ) { s[++top] = p; p = p->lchild; } else { p = s[top--]; printf(" %c", p->data); p = p->rchild; } } } /* 後序非遞迴演算法 */ /* *後序與前、中序不同,需要另一個棧來存放對應入棧的標誌位 *當第三次訪問該節點時才打印該節點 * *--當列印第一個數後,並不會返回執行if,而是執行else if,也就是父節點的右子樹 * */ void PostOrder( BTNode *b ) { BTNode *s1[M], *s2[M], *p = b; int top=-1; while ( p != NULL || top != -1 ) { if ( p != NULL ) { s1[++top] = p; /* 入棧 */ p = p->lchild; s2[top] = 1; /* 第 1 次訪問該節點 */ } else if ( s2[top] == 1 ) { p = s1[top]; p = p->rchild; s2[top] = 2; /* 第 2 次訪問該節點 */ } else { p = s1[top--]; /* 出棧 */ printf(" %c", p->data); p = NULL; /* 跳過直接下次迴圈的 if 語句, 進行 else if 的判斷 */ } } } int main() { BTNode *b; char str[M]; gets( str ); b = createBiTree( str ); /////////////////////////////////////// printf(" Recursion: \n\n"); printf("PreOrder1: "); PreOrder1( b ); /* 先序遞迴演算法 */ printf("\n"); printf("InOrder1: "); InOrder1( b ); /* 中序遞迴演算法 */ printf("\n"); printf("PostOrder1: "); PostOrder1( b ); /* 後序遞迴演算法 */ printf("\n\n\n"); //////////////////////////////////////// printf(" No Recursion: \n\n"); printf("PreOrder: "); PreOrder( b ); printf("\n"); printf("InOrder: "); InOrder( b ); printf("\n"); printf("PostOrder: "); PostOrder( b ); printf("\n"); return 0; }
2.哈夫曼編碼
要求:
- 掌握哈夫曼樹的建立方法;
- 掌握哈夫曼編碼的生成方法。
程式碼:
#include <stdio.h> #include <stdlib.h> #include <limits.h> #define N 8 //字母個數 #define M ( 2*N-1 ) //節點數目 typedef struct /* HaffmanTree 結構體: weight parent lchild rchild */ { int weight; int parent, lchild, rchild; }HTNode; typedef HTNode HaffmanTree[M]; /* HTNode 型別的陣列結構體 */ typedef struct /* HaffmanTree 結構體: data weight code[N] */ { char data; int weight; char code[N]; /* 編碼 原本最長:N-1, 最後一位存放'\0'*/ }HTCode; typedef HTCode HaffmanCode[N]; /* HTCode 型別的陣列結構體 */ /* 初始化 haffmancode */ int initHaffmanCode( HaffmanCode hc ) /* hc 是陣列 */ { int i; for (i=0; i<N; i++) { printf("Please input %d's code and weight: ", i+1); fflush(stdin); /* 清空緩衝區 */ scanf("%c%d", &hc[i].data, &hc[i].weight); } } /*初始化 haffmantree*/ /* *給葉節點賦 weight,其餘賦-1 */ void initHaffmanTree( HaffmanTree ht, HaffmanCode hc ) { int i; for (i=0; i<N; i++) { ht[i].weight = hc[i].weight; /*初始化 weight*/ } for (i=0; i<M; i++) { ht[i].parent = ht[i].lchild = ht[i].rchild = -1; /*賦值 -1*/ } } /*建立 哈夫曼樹*/ void createHaffmanTree( HaffmanTree ht ) { int i, j; int min1, min2, index1, index2; /*最小值、 次小值、 最小值下標、 次小值下標*/ for (i=N; i<M; i++) /*查詢 min1 和 min2*/ { min1 = min2 = INT_MAX; /* int型別的最大值 (引入標頭檔案limts.h)*/ index1 = index2 = -1; for (j=0; j<i; j++) /*注:每次查詢的範圍在擴大(+1)*/ { if (ht[j].parent == -1) /*沒有雙親才比較*/ { if (ht[j].weight < min1) /* ht[j].weight < min1 < min2 */ { min2 = min1; /*原來的最小值變為了次小值*/ index2 = index1; min1 = ht[j].weight; /*新的最小值為 ht[j].weight */ index1 = j; } else if(ht[j].weight < min2) { min2 = ht[j].weight; /* min1 < ht[j].weight < min2 */ index2 = j; } } } ht[i].weight = min1 + min2; /* 計算新權值,最小值 和 次小值相加得到二者的雙親節點的權值 */ ht[i].lchild = index1; /* 最小值在左 */ ht[i].rchild = index2; /* 次小在右 */ /* 修改父節點 */ ht[index1].parent = ht[index2].parent = i; /* 最小值 和 次小值的 parent */ /* 修改兩個子樹節點 */ } } /*建立 哈夫曼程式碼*/ void createHaffmanCode( HaffmanTree ht, HaffmanCode hc ) { char code[N]; /*暫時存放哈夫曼程式碼*/ int i, j, start; for (i=0; i<N; i++) /*倒敘查詢*/ { start = N - 1; code[start] = '\0'; j = i; while(ht[j].parent != -1) /*到達根節點跳出*/ { code[--start] = ht[ht[j].parent].lchild == j?'0':'1'; /* 雙親的lchild == 該節點的下標,即值為0,否則為1 */ j = ht[j].parent; /*雙親的下標*/ } strcpy(hc[i].code, &code[start]); /*code 是陣列, 有值的地方的地址(因為是倒敘)賦給 hc[i].code(相當於賦首地址)*/ } } /*列印 code*/ void printCode( HaffmanCode hc ) { int i; for (i=0; i<N; i++) { printf("%c的編碼是: %s\n", hc[i].data, hc[i].code); } } int main() { HaffmanCode hc; HaffmanTree ht; initHaffmanCode(hc); /*初始化*/ initHaffmanTree(ht, hc); createHaffmanTree(ht); /*建立*/ createHaffmanCode(ht, hc); printCode(hc); return 0; }
3. 佇列
要求:
1. 輸入說明:輸入為一行正整數,其中第1個數字N(N<=1000)為顧客總數,後面跟著N位顧客的編號。編號為奇數的顧客需要到A視窗辦理業務,為偶數顧客則去B視窗。數字以空格分隔。
2. 輸出說明:按業務處理完成的順序輸出顧客的編號。數字間以空格分隔,但最後一個編號不能有多餘的空格。
Question I:從鍵盤接收顧客編號
Question II:隨機生成顧客編號
Question III:按照 A-B 視窗處理速度
程式碼:
#include <stdio.h> #include <stdlib.h> typedef struct node /* 指向資料的結構體 */ { int Data; struct node *Next; } Qnode; typedef struct link /* 指向節點的結構體 */ { Qnode *Front, *Rear; struct link *Next; } LinkQueue; /* 初始化 */ LinkQueue *initQueue() { LinkQueue *q; Qnode *p; q = (LinkQueue *)malloc(sizeof(LinkQueue)); q->Front = q->Rear = (Qnode *)malloc(sizeof(Qnode)); q->Front->Next = NULL; return q; } /* 是否為空,為空返回1 */ int isEmpty( LinkQueue *q ) { if ( q->Front == q->Rear ) return 1; else return 0; } /* 入隊 A 視窗*/ void EnqueueA( LinkQueue *q, int data ) { Qnode *p; p = (Qnode *)malloc(sizeof(Qnode)); p->Data = data; p->Next = NULL; q->Rear->Next = p; q->Rear = p; } /* 入隊 B 視窗 */ void EnqueueB( LinkQueue *q, int data ) { Qnode *p; p = (Qnode *)malloc(sizeof(Qnode)); p->Data = data; p->Next = NULL; q->Rear->Next = p; q->Rear = p; } /* 出隊 */ void OutQueue( LinkQueue *q, int *queue ) { if ( isEmpty(q) ) return '#'; Qnode *p, *m; p = q->Front->Next; q->Front->Next = p->Next; /* 隊頭指向下一個節點 */ *queue = p->Data; m = q->Front; while( m->Next ) /* m 指向隊尾*/ m = m->Next; q->Rear = m; } /* Question I II 列印語句 */ void print( int N, LinkQueue *qA, LinkQueue *qB, int *queue ) { int i, flag=0; /* flag 判斷 A 出隊次數 */ /* 入隊 */ for ( i=0; i<N; i++ ) { if ( queue[i]%2 == 1 ) /* 奇數到 A 視窗 */ { EnqueueA( qA, queue[i] ); } else /* 偶數到 B 視窗 */ EnqueueB( qB, queue[i] ); } /* 出隊 */ for ( i=0; i<N; i++ ) { if ( flag < 2 && !isEmpty( qA )) /* A 出隊 */ { OutQueue( qA, &queue[i] ); flag++; } else if ( !isEmpty( qB ) ) /* B 出隊 */ { OutQueue( qB, &queue[i] ); flag = 0; } else { if ( !isEmpty( qA ) ) OutQueue( qA, &queue[i] ); else if ( !isEmpty( qB ) ) OutQueue( qB, &queue[i] ); flag = 0; } } printf("The order of queue: "); for ( i=0; i<N; i++ ) printf(" %d", queue[i]); printf("\n"); } /* Question III 列印語句 */ void print2( int N, int NA, int NB, LinkQueue *qA, LinkQueue *qB, int *queue ) { int i, flag=0, flag2=0; /* flag 判斷 A 出隊次數, flag2 判斷 B 出隊次數 */ /* 入隊 */ for ( i=0; i<N; i++ ) { if ( queue[i]%2 == 1 ) /* 奇數到 A 視窗 */ { EnqueueA( qA, queue[i] ); } else /* 偶數到 B 視窗 */ EnqueueB( qB, queue[i] ); } /* 出隊 */ for ( i=0; i<N; i++ ) { if ( flag < NA && !isEmpty( qA )) /* A 出隊 */ { OutQueue( qA, &queue[i] ); flag++; flag2 = 0; } else if ( !isEmpty( qB ) ) /* B 出隊 */ { OutQueue( qB, &queue[i] ); flag2++; if ( flag2 >= NB ) /* 判斷 B 出隊次數是否滿足 */ flag = 0; } else { if ( !isEmpty( qA ) ) OutQueue( qA, &queue[i] ); else if ( !isEmpty( qB ) ) OutQueue( qB, &queue[i] ); flag = 0; flag2 = 0; } } printf("The order of queue: "); for ( i=0; i<N; i++ ) printf(" %d", queue[i]); printf("\n"); } int main() { LinkQueue *qA, *qB; int N; int queue[1000], i; int NA, NB; qA = initQueue(); qB = initQueue(); printf("Question I:\n"); /* 從鍵盤接收 */ printf("N: "); scanf("%d", &N); for ( i=0; i<N; i++ ) scanf("%d", &queue[i]); print( N, qA, qB, queue ); //////////////////////////////////////////////////// printf("\n"); printf("Question II:\n"); /* 按照 rand() 計算 */ printf("N: "); scanf("%d", &N); for ( i=0; i<N; i++ ) queue[i] = rand()%1000+1; printf("The rand number: "); for(i=0; i<N; i++) printf("%d ", queue[i]); printf("\n"); print( N, qA, qB, queue ); //////////////////////////////////////////////////// printf("\n"); printf("Question III:\n"); /* 按照 NA : NB 計算 */ printf("N: "); scanf("%d", &N); printf("NA:NB: "); scanf("%d%d", &NA, &NB); for ( i=0; i<N; i++ ) queue[i] = rand()%1000+1; printf("The rand number: "); for(i=0; i<N; i++) printf("%d ", queue[i]); printf("\n"); print2( N, NA, NB, qA, qB, queue ); return 0; }