树的应用

来源:互联网 发布:怎么看端口是否开放 编辑:程序博客网 时间:2024/06/05 17:38

1.公共部分

#include "DSTree.h"typedef struct{char ch;DLTree p;}SElemType; /* 定义栈元素类型 */#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */#define STACKINCREMENT 2 /* 存储空间分配增量 */typedef struct SqStack{SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */SElemType *top; /* 栈顶指针 */int stacksize; /* 当前已分配的存储空间,以元素为单位 */}SqStack; /* 顺序栈 *//* bo3-1.c 顺序栈(存储结构由c3-1.h定义)的基本操作(9个) */Status InitStack(SqStack *S);Status DestroyStack(SqStack *S);Status ClearStack(SqStack *S);Status StackEmpty(SqStack S);int StackLength(SqStack S);Status GetTop(SqStack S, SElemType *e);Status Push(SqStack *S, SElemType e);Status Pop(SqStack *S, SElemType *e);Status StackTraverse(SqStack S, Status(*visit)(SElemType));

/* bo3-1.c 顺序栈(存储结构由c3-1.h定义)的基本操作(9个) */#include "stack.h"Status InitStack(SqStack *S){ /* 构造一个空栈S */(*S).base = (SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));if (!(*S).base)exit(OVERFLOW); /* 存储分配失败 */(*S).top = (*S).base;(*S).stacksize = STACK_INIT_SIZE;return OK;}Status DestroyStack(SqStack *S){ /* 销毁栈S,S不再存在 */free((*S).base);(*S).base = NULL;(*S).top = NULL;(*S).stacksize = 0;return OK;}Status ClearStack(SqStack *S){ /* 把S置为空栈 */(*S).top = (*S).base;return OK;}Status StackEmpty(SqStack S){ /* 若栈S为空栈,则返回TRUE,否则返回FALSE */if (S.top == S.base)return TRUE;elsereturn FALSE;}int StackLength(SqStack S){ /* 返回S的元素个数,即栈的长度 */return S.top - S.base;}Status GetTop(SqStack S, SElemType *e){ /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */if (S.top>S.base){*e = *(S.top - 1);return OK;}elsereturn ERROR;}Status Push(SqStack *S, SElemType e){ /* 插入元素e为新的栈顶元素 */if ((*S).top - (*S).base >= (*S).stacksize) /* 栈满,追加存储空间 */{(*S).base = (SElemType *)realloc((*S).base, ((*S).stacksize + STACKINCREMENT)*sizeof(SElemType));if (!(*S).base)exit(OVERFLOW); /* 存储分配失败 */(*S).top = (*S).base + (*S).stacksize;(*S).stacksize += STACKINCREMENT;}*((*S).top)++ = e;return OK;}Status Pop(SqStack *S, SElemType *e){ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */if ((*S).top == (*S).base)return ERROR;*e = *--(*S).top;return OK;}Status StackTraverse(SqStack S, Status(*visit)(SElemType)){ /* 从栈底到栈顶依次对栈中每个元素调用函数visit()。 *//* 一旦visit()失败,则操作失败 */while (S.top>S.base)visit(*S.base++);printf("\n");return OK;}

2.二叉查找树

/* c1.h (程序名) */#include<string.h>#include<ctype.h>#include<malloc.h> /* malloc()等 */#include<limits.h> /* INT_MAX等 */#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<stdlib.h> /* atoi() */#include<io.h> /* eof() */#include<math.h> /* floor(),ceil(),abs() */#include<process.h> /* exit() *//* 函数结果状态代码 */#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASIBLE -1#define EQ(a,b) ((a)==(b))#define LT(a,b) ((a)<(b))#define LQ(a,b) ((a)<=(b))/* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */#define N 10 /* 数据元素个数 */typedef int KeyType; /* 设关键字域为整型 */typedef struct{KeyType key;int others;} ElemType; /* 数据元素类型 */typedef ElemType TElemType;typedef struct BiTNode{TElemType data;struct BiTNode *lchild, *rchild; /* 左右孩子指针 */}BiTNode, *BiTree;Status InitDSTable(BiTree *DT);void DestroyDSTable(BiTree *DT);BiTree SearchBST(BiTree T, KeyType key);void SearchBST1(BiTree *T, KeyType key, BiTree f, BiTree *p, Status *flag);Status InsertBST(BiTree *T, ElemType e);void Delete(BiTree *p);Status DeleteBST(BiTree *T, KeyType key);void TraverseDSTable(BiTree DT, void(*Visit)(ElemType));

#include "BST.h"Status InitDSTable(BiTree *DT) /* 同bo6-2.c */{ /* 操作结果: 构造一个空的动态查找表DT */*DT = NULL;return OK;}void DestroyDSTable(BiTree *DT) /* 同bo6-2.c */{ /* 初始条件: 动态查找表DT存在。操作结果: 销毁动态查找表DT */if (*DT) /* 非空树 */{if ((*DT)->lchild) /* 有左孩子 */DestroyDSTable(&(*DT)->lchild); /* 销毁左孩子子树 */if ((*DT)->rchild) /* 有右孩子 */DestroyDSTable(&(*DT)->rchild); /* 销毁右孩子子树 */free(*DT); /* 释放根结点 */*DT = NULL; /* 空指针赋0 */}}BiTree SearchBST(BiTree T, KeyType key){ /* 在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素, *//* 若查找成功,则返回指向该数据元素结点的指针,否则返回空指针。算法9.5(a) */if ((!T) || EQ(key, T->data.key))return T; /* 查找结束 */else if LT(key, T->data.key) /* 在左子树中继续查找 */return SearchBST(T->lchild, key);elsereturn SearchBST(T->rchild, key); /* 在右子树中继续查找 */}void SearchBST1(BiTree *T, KeyType key, BiTree f, BiTree *p, Status *flag) /* 算法9.5(b)改 */{ /* 在根指针T所指二叉排序树中递归地查找其关键字等于key的数据元素,若查找 *//* 成功,则指针p指向该数据元素结点,并返回TRUE,否则指针p指向查找路径上 *//* 访问的最后一个结点并返回FALSE,指针f指向T的双亲,其初始调用值为NULL */if (!*T) /* 查找不成功 */{*p = f;*flag = FALSE;}else if EQ(key, (*T)->data.key) /*  查找成功 */{*p = *T;*flag = TRUE;}else if LT(key, (*T)->data.key)SearchBST1(&(*T)->lchild, key, *T, p, flag); /* 在左子树中继续查找 */elseSearchBST1(&(*T)->rchild, key, *T, p, flag); /*  在右子树中继续查找 */}Status InsertBST(BiTree *T, ElemType e){ /* 当二叉排序树T中不存在关键字等于e.key的数据元素时,插入e并返回TRUE, *//* 否则返回FALSE。算法9.6(改) */BiTree p, s;Status flag;SearchBST1(T, e.key, NULL, &p, &flag);if (!flag) /* 查找不成功 */{s = (BiTree)malloc(sizeof(BiTNode));s->data = e;s->lchild = s->rchild = NULL;if (!p)*T = s; /* 被插结点*s为新的根结点 */else if LT(e.key, p->data.key)p->lchild = s; /* 被插结点*s为左孩子 */elsep->rchild = s; /* 被插结点*s为右孩子 */return TRUE;}elsereturn FALSE; /* 树中已有关键字相同的结点,不再插入 */}void Delete(BiTree *p){ /* 从二叉排序树中删除结点p,并重接它的左或右子树。算法9.8 */BiTree q, s;if (!(*p)->rchild) /* 右子树空则只需重接它的左子树(待删结点是叶子也走此分支) */{q = *p;*p = (*p)->lchild;free(q);}else if (!(*p)->lchild) /* 只需重接它的右子树 */{q = *p;*p = (*p)->rchild;free(q);}else /* 左右子树均不空 */{q = *p;s = (*p)->lchild;while (s->rchild) /* 转左,然后向右到尽头(找待删结点的前驱) */{q = s;s = s->rchild;}(*p)->data = s->data; /* s指向被删结点的"前驱"(将被删结点前驱的值取代被删结点的值) */if (q != *p)q->rchild = s->lchild; /* 重接*q的右子树 */elseq->lchild = s->lchild; /* 重接*q的左子树 */free(s);}}Status DeleteBST(BiTree *T, KeyType key){ /* 若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素结点, *//* 并返回TRUE;否则返回FALSE。算法9.7 */if (!*T) /* 不存在关键字等于key的数据元素 */return FALSE;else{if EQ(key, (*T)->data.key) /* 找到关键字等于key的数据元素 */Delete(T);else if LT(key, (*T)->data.key)DeleteBST(&(*T)->lchild, key);elseDeleteBST(&(*T)->rchild, key);return TRUE;}}void TraverseDSTable(BiTree DT, void(*Visit)(ElemType)){ /* 初始条件: 动态查找表DT存在,Visit是对结点操作的应用函数 *//* 操作结果: 按关键字的顺序对DT的每个结点调用函数Visit()一次且至多一次 */if (DT){TraverseDSTable(DT->lchild, Visit); /* 先中序遍历左子树 */Visit(DT->data); /* 再访问根结点 */TraverseDSTable(DT->rchild, Visit); /* 最后中序遍历右子树 */}}

#include "BST.h"void print(ElemType c){printf("(%d,%d) ", c.key, c.others);}void main(){BiTree dt, p;int i;KeyType j;ElemType r[N] = { { 45, 1 }, { 12, 2 }, { 53, 3 }, { 3, 4 }, { 37, 5 }, { 24, 6 }, { 100, 7 }, { 61, 8 }, { 90, 9 }, { 78, 10 } }; /* 以教科书图9.7(a)为例 */InitDSTable(&dt); /* 构造空表 */for (i = 0; i<N; i++)InsertBST(&dt, r[i]); /* 依次插入数据元素 */TraverseDSTable(dt, print);printf("\n请输入待查找的值: ");scanf("%d", &j);p = SearchBST(dt, j);if (p){printf("表中存在此值。");DeleteBST(&dt, j);printf("删除此值后:\n");TraverseDSTable(dt, print);printf("\n");}elseprintf("表中不存在此值\n");DestroyDSTable(&dt);}

3.AVL树

#include<string.h>#include<ctype.h>#include<malloc.h> /* malloc()等 */#include<limits.h> /* INT_MAX等 */#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<stdlib.h> /* atoi() */#include<io.h> /* eof() */#include<math.h> /* floor(),ceil(),abs() */#include<process.h> /* exit() *//* 函数结果状态代码 */#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASIBLE -1#define EQ(a,b) ((a)==(b))#define LT(a,b) ((a)<(b))#define LQ(a,b) ((a)<=(b))#define LH +1 /* 左高 */#define EH 0  /* 等高 */#define RH -1 /* 右高 *//* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */#define N 5 /* 数据元素个数 */typedef char KeyType; /* 设关键字域为字符型 */typedef struct{KeyType key;int order;}ElemType; /* 数据元素类型 */typedef struct BSTNode{ElemType data;int bf; /* 结点的平衡因子 */struct BSTNode *lchild, *rchild; /* 左、右孩子指针 */}BSTNode, *BSTree;Status InitDSTable(BSTree *DT);void DestroyDSTable(BSTree *DT);BSTree SearchBST(BSTree T, KeyType key);void R_Rotate(BSTree *p);void L_Rotate(BSTree *p);void LeftBalance(BSTree *T);void RightBalance(BSTree *T);Status InsertAVL(BSTree *T, ElemType e, Status *taller);void TraverseDSTable(BSTree DT, void(*Visit)(ElemType));

#include "AVL.h"Status InitDSTable(BSTree *DT) /* 同bo6-2.c */{ /* 操作结果: 构造一个空的动态查找表DT */*DT = NULL;return OK;}////////////////////////////////////////////////wrongvoid DestroyDSTable(BSTree *DT) /* 同bo6-2.c */{ /* 初始条件: 动态查找表DT存在。操作结果: 销毁动态查找表DT */if (*DT) /* 非空树 */{if ((*DT)->lchild) /* 有左孩子 */DestroyDSTable(&(*DT)->lchild); /* 销毁左孩子子树 */if ((*DT)->rchild) /* 有右孩子 */DestroyDSTable(&(*DT)->rchild); /* 销毁右孩子子树 */free(*DT); /* 释放根结点 */*DT = NULL; /* 空指针赋0 */}}BSTree SearchBST(BSTree T, KeyType key){ /* 在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素, *//* 若查找成功,则返回指向该数据元素结点的指针,否则返回空指针。算法9.5(a) */if ((!T) || EQ(key, T->data.key))return T; /* 查找结束 */else if LT(key, T->data.key) /* 在左子树中继续查找 */return SearchBST(T->lchild, key);elsereturn SearchBST(T->rchild, key); /* 在右子树中继续查找 */}void R_Rotate(BSTree *p){ /* 对以*p为根的二叉排序树作右旋处理,处理之后p指向新的树根结点,即旋转 *//* 处理之前的左子树的根结点。算法9.9 */BSTree lc;lc = (*p)->lchild; /* lc指向p的左子树根结点 */(*p)->lchild = lc->rchild; /* lc的右子树挂接为p的左子树 */lc->rchild = *p;*p = lc; /* p指向新的根结点 */}void L_Rotate(BSTree *p){ /* 对以*p为根的二叉排序树作左旋处理,处理之后p指向新的树根结点,即旋转 *//* 处理之前的右子树的根结点。算法9.10 */BSTree rc;rc = (*p)->rchild; /* rc指向p的右子树根结点 */(*p)->rchild = rc->lchild; /* rc的左子树挂接为p的右子树 */rc->lchild = *p;*p = rc; /* p指向新的根结点 */}#define LH +1 /* 左高 */#define EH 0  /* 等高 */#define RH -1 /* 右高 */void LeftBalance(BSTree *T){ /* 对以指针T所指结点为根的二叉树作左平衡旋转处理,本算法结束时, *//* 指针T指向新的根结点。算法9.12 */BSTree lc, rd;lc = (*T)->lchild; /* lc指向*T的左子树根结点 */switch (lc->bf){ /* 检查*T的左子树的平衡度,并作相应平衡处理 */case LH: /* 新结点插入在*T的左孩子的左子树上,要作单右旋处理 */(*T)->bf = lc->bf = EH;R_Rotate(T);break;case RH: /* 新结点插入在*T的左孩子的右子树上,要作双旋处理 */rd = lc->rchild; /* rd指向*T的左孩子的右子树根 */switch (rd->bf){ /* 修改*T及其左孩子的平衡因子 */case LH: (*T)->bf = RH;lc->bf = EH;break;case EH: (*T)->bf = lc->bf = EH;break;case RH: (*T)->bf = EH;lc->bf = LH;}rd->bf = EH;L_Rotate(&(*T)->lchild); /* 对*T的左子树作左旋平衡处理 */R_Rotate(T); /* 对*T作右旋平衡处理 */}}void RightBalance(BSTree *T){ /* 对以指针T所指结点为根的二叉树作右平衡旋转处理,本算法结束时, *//* 指针T指向新的根结点 */BSTree rc, rd;rc = (*T)->rchild; /* rc指向*T的右子树根结点 */switch (rc->bf){ /* 检查*T的右子树的平衡度,并作相应平衡处理 */case RH: /* 新结点插入在*T的右孩子的右子树上,要作单左旋处理 */(*T)->bf = rc->bf = EH;L_Rotate(T);break;case LH: /* 新结点插入在*T的右孩子的左子树上,要作双旋处理 */rd = rc->lchild; /* rd指向*T的右孩子的左子树根 */switch (rd->bf){ /* 修改*T及其右孩子的平衡因子 */case RH: (*T)->bf = LH;rc->bf = EH;break;case EH: (*T)->bf = rc->bf = EH;break;case LH: (*T)->bf = EH;rc->bf = RH;}rd->bf = EH;R_Rotate(&(*T)->rchild); /* 对*T的右子树作右旋平衡处理 */L_Rotate(T); /* 对*T作左旋平衡处理 */}}Status InsertAVL(BSTree *T, ElemType e, Status *taller){ /* 若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个 *//* 数据元素为e的新结点,并返回1,否则返回0。若因插入而使二叉排序树 *//* 失去平衡,则作平衡旋转处理,布尔变量taller反映T长高与否。算法9.11 */if (!*T){ /* 插入新结点,树“长高”,置taller为TRUE */*T = (BSTree)malloc(sizeof(BSTNode));(*T)->data = e;(*T)->lchild = (*T)->rchild = NULL;(*T)->bf = EH;*taller = TRUE;}else{if EQ(e.key, (*T)->data.key){ /* 树中已存在和e有相同关键字的结点则不再插入 */*taller = FALSE;return FALSE;}if LT(e.key, (*T)->data.key){ /* 应继续在*T的左子树中进行搜索 */if (!InsertAVL(&(*T)->lchild, e, taller)) /* 未插入 */return FALSE;if (*taller) /*  已插入到*T的左子树中且左子树“长高” */switch ((*T)->bf) /* 检查*T的平衡度 */{case LH: /* 原本左子树比右子树高,需要作左平衡处理 */LeftBalance(T);*taller = FALSE;break;case EH: /* 原本左、右子树等高,现因左子树增高而使树增高 */(*T)->bf = LH;*taller = TRUE;break;case RH: (*T)->bf = EH; /* 原本右子树比左子树高,现左、右子树等高 */*taller = FALSE;}}else{ /* 应继续在*T的右子树中进行搜索 */if (!InsertAVL(&(*T)->rchild, e, taller)) /* 未插入 */return FALSE;if (*taller) /* 已插入到T的右子树且右子树“长高” */switch ((*T)->bf) /* 检查T的平衡度 */{case LH: (*T)->bf = EH; /* 原本左子树比右子树高,现左、右子树等高 */*taller = FALSE;break;case EH: /* 原本左、右子树等高,现因右子树增高而使树增高 */(*T)->bf = RH;*taller = TRUE;break;case RH: /* 原本右子树比左子树高,需要作右平衡处理 */RightBalance(T);*taller = FALSE;}}}return TRUE;}void TraverseDSTable(BSTree DT, void(*Visit)(ElemType)){ /* 初始条件: 动态查找表DT存在,Visit是对结点操作的应用函数 *//* 操作结果: 按关键字的顺序对DT的每个结点调用函数Visit()一次且至多一次 */if (DT){TraverseDSTable(DT->lchild, Visit); /* 先中序遍历左子树 */Visit(DT->data); /* 再访问根结点 */TraverseDSTable(DT->rchild, Visit); /* 最后中序遍历右子树 */}}

#include "AVL.h"void print(ElemType c){printf("(%d,%d)", c.key, c.order);}void main(){BSTree dt, p;Status k;int i;KeyType j;ElemType r[N] = { { 13, 1 }, { 24, 2 }, { 37, 3 }, { 90, 4 }, { 53, 5 } }; /* (以教科书图9.12为例) */InitDSTable(&dt); /* 初始化空树 */for (i = 0; i<N; i++)InsertAVL(&dt, r[i], &k); /* 建平衡二叉树 */TraverseDSTable(dt, print); /* 按关键字顺序遍历二叉树 */printf("\n请输入待查找的关键字: ");scanf("%d", &j);p = SearchBST(dt, j); /* 查找给定关键字的记录 */if (p)print(p->data);elseprintf("表中不存在此值");printf("\n");//wrongDestroyDSTable(&dt);}

4.B树

#include<string.h>#include<ctype.h>#include<malloc.h> /* malloc()等 */#include<limits.h> /* INT_MAX等 */#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<stdlib.h> /* atoi() */#include<io.h> /* eof() */#include<math.h> /* floor(),ceil(),abs() */#include<process.h> /* exit() *//* 函数结果状态代码 */#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASIBLE -1#define EQ(a,b) ((a)==(b))#define LT(a,b) ((a)<(b))#define LQ(a,b) ((a)<=(b))#define m 3 /* B树的阶,暂设为3 */#define N 16 /* 数据元素个数 */#define MAX 5 /* 字符串最大长度+1 */typedef int KeyType; /* 设关键字域为整型 */* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */typedef struct{char info[MAX];}Others;/* 记录的其它部分 */* c9-3.h B树的结点类型 */typedef struct{KeyType key; /* 关键字 */Others others; /* 其它部分(由主程定义) */}Record; /* 记录类型 */typedef struct BTNode{int keynum; /* 结点中关键字个数,即结点的大小 */struct BTNode *parent; /* 指向双亲结点 */struct Node /* 结点向量类型 */{KeyType key; /* 关键字向量 */struct BTNode *ptr; /* 子树指针向量 */Record *recptr; /* 记录指针向量 */}node[m + 1]; /* key,recptr的0号单元未用 */}BTNode, *BTree; /* B树结点和B树的类型 */typedef struct{BTNode *pt; /* 指向找到的结点 */int i; /* 1..m,在结点中的关键字序号 */int tag; /* 1:查找成功,O:查找失败 */}Result; /* B树的查找结果类型 */Status InitDSTable(BTree *DT);void DestroyDSTable(BTree *DT);int Search(BTree p, KeyType K);Result SearchBTree(BTree T, KeyType K);void Insert(BTree *q, int i, Record *r, BTree ap);void split(BTree *q, BTree *ap);void NewRoot(BTree *T, Record *r, BTree ap);void InsertBTree(BTree *T, Record *r, BTree q, int i);void TraverseDSTable(BTree DT, void(*Visit)(BTNode, int));

#include "BTree.h"Status InitDSTable(BTree *DT){ /* 操作结果: 构造一个空的动态查找表DT */*DT = NULL;return OK;}void DestroyDSTable(BTree *DT){ /* 初始条件: 动态查找表DT存在。操作结果: 销毁动态查找表DT */int i;if (*DT) /* 非空树 */{for (i = 0; i <= (*DT)->keynum; i++)DestroyDSTable(&(*DT)->node[i].ptr); /* 依次销毁第i棵子树 */free(*DT); /* 释放根结点 */*DT = NULL; /* 空指针赋0 */}}int Search(BTree p, KeyType K){ /* 在p->node[1..keynum].key中查找i,使得p->node[i].key≤K<p->node[i+1].key */int i = 0, j;for (j = 1; j <= p->keynum; j++)if (p->node[j].key <= K)i = j;return i;}Result SearchBTree(BTree T, KeyType K){ /* 在m阶B树T上查找关键字K,返回结果(pt,i,tag)。若查找成功,则特征值 *//* tag=1,指针pt所指结点中第i个关键字等于K;否则特征值tag=0,等于K的 *//* 关键字应插入在指针Pt所指结点中第i和第i+1个关键字之间。算法9.13 */BTree p = T, q = NULL; /* 初始化,p指向待查结点,q指向p的双亲 */Status found = FALSE;int i = 0;Result r;while (p&&!found){i = Search(p, K); /* p->node[i].key≤K<p->node[i+1].key */if (i>0 && p->node[i].key == K) /* 找到待查关键字 */found = TRUE;else{q = p;p = p->node[i].ptr;}}r.i = i;if (found) /* 查找成功 */{r.pt = p;r.tag = 1;}else /*  查找不成功,返回K的插入位置信息 */{r.pt = q;r.tag = 0;}return r;}void Insert(BTree *q, int i, Record *r, BTree ap){ /* 将r->key、r和ap分别插入到q->key[i+1]、q->recptr[i+1]和q->ptr[i+1]中 */int j;for (j = (*q)->keynum; j>i; j--) /* 空出q->node[i+1] */(*q)->node[j + 1] = (*q)->node[j];(*q)->node[i + 1].key = r->key;(*q)->node[i + 1].ptr = ap;(*q)->node[i + 1].recptr = r;(*q)->keynum++;}void split(BTree *q, BTree *ap){ /* 将结点q分裂成两个结点,前一半保留,后一半移入新生结点ap */int i, s = (m + 1) / 2;*ap = (BTree)malloc(sizeof(BTNode)); /* 生成新结点ap */(*ap)->node[0].ptr = (*q)->node[s].ptr; /* 后一半移入ap */for (i = s + 1; i <= m; i++){(*ap)->node[i - s] = (*q)->node[i];if ((*ap)->node[i - s].ptr)(*ap)->node[i - s].ptr->parent = *ap;}(*ap)->keynum = m - s;(*ap)->parent = (*q)->parent;(*q)->keynum = s - 1; /* q的前一半保留,修改keynum */}void NewRoot(BTree *T, Record *r, BTree ap){ /* 生成含信息(T,r,ap)的新的根结点*T,原T和ap为子树指针 */BTree p;p = (BTree)malloc(sizeof(BTNode));p->node[0].ptr = *T;*T = p;if ((*T)->node[0].ptr)(*T)->node[0].ptr->parent = *T;(*T)->parent = NULL;(*T)->keynum = 1;(*T)->node[1].key = r->key;(*T)->node[1].recptr = r;(*T)->node[1].ptr = ap;if ((*T)->node[1].ptr)(*T)->node[1].ptr->parent = *T;}void InsertBTree(BTree *T, Record *r, BTree q, int i){ /* 在m阶B树T上结点*q的key[i]与key[i+1]之间插入关键字K的指针r。若引起 *//* 结点过大,则沿双亲链进行必要的结点分裂调整,使T仍是m阶B树。算法9.14改 */BTree ap = NULL;Status finished = FALSE;int s;Record *rx;rx = r;while (q&&!finished){Insert(&q, i, rx, ap); /* 将r->key、r和ap分别插入到q->key[i+1]、q->recptr[i+1]和q->ptr[i+1]中 */if (q->keynum<m)finished = TRUE; /* 插入完成 */else{ /* 分裂结点*q */s = (m + 1) / 2;rx = q->node[s].recptr;split(&q, &ap); /* 将q->key[s+1..m],q->ptr[s..m]和q->recptr[s+1..m]移入新结点*ap */q = q->parent;if (q)i = Search(q, rx->key); /* 在双亲结点*q中查找rx->key的插入位置 */}}if (!finished) /* T是空树(参数q初值为NULL)或根结点已分裂为结点*q和*ap */NewRoot(T, rx, ap); /* 生成含信息(T,rx,ap)的新的根结点*T,原T和ap为子树指针 */}void TraverseDSTable(BTree DT, void(*Visit)(BTNode, int)){ /* 初始条件: 动态查找表DT存在,Visit是对结点操作的应用函数 *//* 操作结果: 按关键字的顺序对DT的每个结点调用函数Visit()一次且至多一次 */int i;if (DT) /* 非空树 */{if (DT->node[0].ptr) /* 有第0棵子树 */TraverseDSTable(DT->node[0].ptr, Visit);for (i = 1; i <= DT->keynum; i++){Visit(*DT, i);if (DT->node[i].ptr) /* 有第i棵子树 */TraverseDSTable(DT->node[i].ptr, Visit);}}}

#include "BTree.h"void print(BTNode c, int i) /* TraverseDSTable()调用的函数 */{printf("(%d,%s)", c.node[i].key, c.node[i].recptr->others.info);}void main(){Record r[N] = { { 24, "1" }, { 45, "2" }, { 53, "3" }, { 12, "4" }, { 37, "5" },{ 50, "6" }, { 61, "7" }, { 90, "8" }, { 100, "9" }, { 70, "10" },{ 3, "11" }, { 30, "12" }, { 26, "13" }, { 85, "14" }, { 3, "15" },{ 7, "16" } }; /* (以教科书中图9.16为例) */BTree t;Result s;int i;InitDSTable(&t);for (i = 0; i<N; i++){s = SearchBTree(t, r[i].key);if (!s.tag)InsertBTree(&t, &r[i], s.pt, s.i);}printf("按关键字的顺序遍历B_树:\n");TraverseDSTable(t, print);printf("\n请输入待查找记录的关键字: ");scanf("%d", &i);s = SearchBTree(t, i);if (s.tag)print(*(s.pt), s.i);elseprintf("没找到");printf("\n");DestroyDSTable(&t);}

5.双链树

#ifndef DSTREE_H#define DSTREE_H#include<string.h>#include<ctype.h>#include<malloc.h> /* malloc()等 */#include<limits.h> /* INT_MAX等 */#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<stdlib.h> /* atoi() */#include<io.h> /* eof() */#include<math.h> /* floor(),ceil(),abs() */#include<process.h> /* exit() *//* 函数结果状态代码 */#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASIBLE -1#define EQ(a,b) ((a)==(b))#define LT(a,b) ((a)<(b))#define LQ(a,b) ((a)<=(b))#define Nil ' ' /* 定义结束符为空格(与教科书不同) */#define m 3 /* B树的阶,暂设为3 */#define N 16 /* 数据元素个数 */#define MAX 5 /* 字符串最大长度+1 */typedef int KeyType; /* 设关键字域为整型 * /* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */#define N 16 /* 数据元素个数 */typedef struct{int ord;}Others; /* 记录的其它部分 *//* c9-4.h 双链树的存储结构 */#define MAXKEYLEN 16 /* 关键字的最大长度 */typedef struct{char ch[MAXKEYLEN]; /* 关键字 */int num; /* 关键字长度 */}KeysType; /* 关键字类型 */typedef struct{KeysType key; /* 关键字 */Others others; /* 其它部分(由主程定义) */}Record; /* 记录类型 */typedef enum{ LEAF, BRANCH }NodeKind; /* 结点种类:{叶子,分支} */typedef struct DLTNode /* 双链树类型 */{char symbol;struct DLTNode *next; /* 指向兄弟结点的指针 */NodeKind kind;union{Record *infoptr; /* 叶子结点的记录指针 */struct DLTNode *first; /* 分支结点的孩子链指针 */}a;}DLTNode, *DLTree;Status InitDSTable(DLTree *DT);void DestroyDSTable(DLTree *DT);Record *SearchDLTree(DLTree T, KeysType K);void InsertDSTable(DLTree *DT, Record *r);void TraverseDSTable(DLTree DT, void(*Vi)(Record));#endif

#include "DSTree.h"#include "stack.h"Status InitDSTable(DLTree *DT){ /* 操作结果: 构造一个空的双链键树DT */*DT = NULL;return OK;}void DestroyDSTable(DLTree *DT){ /* 初始条件: 双链键树DT存在。操作结果: 销毁双链键树DT */if (*DT) /* 非空树 */{if ((*DT)->kind == BRANCH && (*DT)->a.first) /* *DT是分支结点且有孩子 */DestroyDSTable(&(*DT)->a.first); /* 销毁孩子子树 */if ((*DT)->next) /* 有兄弟 */DestroyDSTable(&(*DT)->next); /* 销毁兄弟子树 */free(*DT); /* 释放根结点 */*DT = NULL; /* 空指针赋0 */}}Record *SearchDLTree(DLTree T, KeysType K){ /* 在非空双链键树T中查找关键字等于K的记录,若存在, *//* 则返回指向该记录的指针,否则返回空指针。算法9.15,有改动 */DLTree p;int i;if (T){p = T; /* 初始化 */i = 0;while (p&&i<K.num){while (p&&p->symbol != K.ch[i]) /* 查找关键字的第i位 */p = p->next;if (p&&i<K.num) /* 准备查找下一位 */p = p->a.first;++i;} /* 查找结束 */if (!p) /* 查找不成功 */return NULL;else /* 查找成功 */return p->a.infoptr;}elsereturn NULL; /* 树空 */}void InsertDSTable(DLTree *DT, Record *r){ /* 初始条件: 双链键树DT存在,r为待插入的数据元素的指针 *//* 操作结果: 若DT中不存在其关键字等于(*r).key.ch的数据元素, *//*           则按关键字顺序插r到DT中 */DLTree p = NULL, q = NULL, ap;int i = 0;KeysType K = r->key;if (!*DT&&K.num) /* 空树且关键字符串非空 */{*DT = ap = (DLTree)malloc(sizeof(DLTNode));for (; i<K.num; i++) /* 插入分支结点 */{if (p)p->a.first = ap;ap->next = NULL;ap->symbol = K.ch[i];ap->kind = BRANCH;p = ap;ap = (DLTree)malloc(sizeof(DLTNode));}p->a.first = ap; /* 插入叶子结点 */ap->next = NULL;ap->symbol = Nil;ap->kind = LEAF;ap->a.infoptr = r;}else /* 非空树 */{p = *DT; /* 指向根结点 */while (p&&i<K.num){while (p&&p->symbol<K.ch[i]) /* 沿兄弟结点查找 */{q = p;p = p->next;}if (p&&p->symbol == K.ch[i]) /* 找到与K.ch[i]相符的结点 */{q = p;p = p->a.first; /* p指向将与K.ch[i+1]比较的结点 */++i;}else /* 没找到,插入关键字 */{ap = (DLTree)malloc(sizeof(DLTNode));if (q->a.first == p)q->a.first = ap; /* 在长子的位置插入 */else /* q->next==p */q->next = ap; /* 在兄弟的位置插入 */ap->next = p;ap->symbol = K.ch[i];ap->kind = BRANCH;p = ap;ap = (DLTree)malloc(sizeof(DLTNode));i++;for (; i<K.num; i++) /* 插入分支结点 */{p->a.first = ap;ap->next = NULL;ap->symbol = K.ch[i];ap->kind = BRANCH;p = ap;ap = (DLTree)malloc(sizeof(DLTNode));}p->a.first = ap; /* 插入叶子结点 */ap->next = NULL;ap->symbol = Nil;ap->kind = LEAF;ap->a.infoptr = r;}}}}void TraverseDSTable(DLTree DT, void(*Vi)(Record)){ /* 初始条件: 双链键树DT存在,Vi是对结点操作的应用函数, *//*           ViR是对记录操作的应用函数 *//* 操作结果: 按关键字的顺序输出关键字及其对应的记录 */SqStack s;SElemType e;DLTree p;int i = 0, n = 8;if (DT){InitStack(&s);e.p = DT;e.ch = DT->symbol;Push(&s, e);p = DT->a.first;while (p->kind == BRANCH) /* 分支结点 */{e.p = p;e.ch = p->symbol;Push(&s, e);p = p->a.first;}e.p = p;e.ch = p->symbol;Push(&s, e);Vi(*(p->a.infoptr));i++;while (!StackEmpty(s)){Pop(&s, &e);p = e.p;if (p->next) /* 有兄弟结点 */{p = p->next;while (p->kind == BRANCH) /* 分支结点 */{e.p = p;e.ch = p->symbol;Push(&s, e);p = p->a.first;}e.p = p;e.ch = p->symbol;Push(&s, e);Vi(*(p->a.infoptr));i++;if (i%n == 0)printf("\n"); /* 输出n个元素后换行 */}}}}

#include "DSTree.h"void print(Record e){int i;printf("(");for (i = 0; i<e.key.num; i++)printf("%c", e.key.ch[i]);printf(",%d)", e.others.ord);}void main(){DLTree t;int i;char s[MAXKEYLEN + 1];KeysType k;Record *p;Record r[N] = { { { "CAI" }, 1 }, { { "CAO" }, 2 }, { { "LI" }, 3 }, { { "LAN" }, 4 },{ { "CHA" }, 5 }, { { "CHANG" }, 6 }, { { "WEN" }, 7 }, { { "CHAO" }, 8 },{ { "YUN" }, 9 }, { { "YANG" }, 10 }, { { "LONG" }, 11 }, { { "WANG" }, 12 },{ { "ZHAO" }, 13 }, { { "LIU" }, 14 }, { { "WU" }, 15 }, { { "CHEN" }, 16 } };/* 数据元素(以教科书式9-24为例) */InitDSTable(&t);for (i = 0; i<N; i++){r[i].key.num = strlen(r[i].key.ch);p = SearchDLTree(t, r[i].key);if (!p) /* t中不存在关键字为r[i].key的项 */InsertDSTable(&t, &r[i]);}printf("按关键字符串的顺序遍历双链键树:\n");TraverseDSTable(t, print);printf("\n请输入待查找记录的关键字符串: ");scanf("%s", s);k.num = strlen(s);strcpy(k.ch, s);p = SearchDLTree(t, k);if (p)print(*p);elseprintf("没找到");printf("\n");DestroyDSTable(&t);}

6.Trie树

#ifndef DSTREE_H#define DSTREE_H#include<string.h>#include<ctype.h>#include<malloc.h> /* malloc()等 */#include<limits.h> /* INT_MAX等 */#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<stdlib.h> /* atoi() */#include<io.h> /* eof() */#include<math.h> /* floor(),ceil(),abs() */#include<process.h> /* exit() *//* 函数结果状态代码 */#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASIBLE -1#define Nil ' ' /* 定义结束符为空格(与教科书不同) */#define m 3 /* B树的阶,暂设为3 */#define N 16 /* 数据元素个数 */#define MAX 5 /* 字符串最大长度+1 */typedef int KeyType; /* 设关键字域为整型 * /* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */#define N 16 /* 数据元素个数 */#define LENGTH 27 /* 结点的最大度+1(大写英文字母) */typedef struct{int ord;}Others; /* 记录的其它部分 */#define MAXKEYLEN 16 /* 关键字的最大长度,同c9-4.h */typedef struct{char ch[MAXKEYLEN]; /* 关键字 */int num; /* 关键字长度 */}KeysType; /* 关键字类型,同c9-4.h */typedef struct{KeysType key; /* 关键字 */Others others; /* 其它部分(由主程定义) */}Record; /* 记录类型,同c9-4.h */typedef enum{ LEAF, BRANCH }NodeKind; /* 结点种类:{叶子,分支},同c9-4.h */typedef struct TrieNode /* Trie键树类型 */{NodeKind kind;union{struct /* 叶子结点 */{KeysType K;Record *infoptr;}lf;struct /* 分支结点 */{struct TrieNode *ptr[LENGTH]; /* LENGTH为结点的最大度+1,在主程定义 *//*  int num; 改 */}bh;}a;}TrieNode, *TrieTree;/* 对两个字符串型关键字的比较约定为如下的宏定义 */#define EQ(a,b) (!strcmp((a),(b)))#define LT(a,b) (strcmp((a),(b))<0)#define LQ(a,b) (strcmp((a),(b))<=0)Status InitDSTable(TrieTree *T);void DestroyDSTable(TrieTree *T);int ord(char c);Record *SearchTrie(TrieTree T, KeysType K);void InsertTrie(TrieTree *T, Record *r);void TraverseDSTable(TrieTree T, Status(*Vi)(Record*));#endif

#include "TrieTree.h"Status InitDSTable(TrieTree *T){ /* 操作结果: 构造一个空的Trie键树T */*T = NULL;return OK;}void DestroyDSTable(TrieTree *T){ /* 初始条件: Trie树T存在。操作结果: 销毁Trie树T */int i;if (*T) /* 非空树 */{for (i = 0; i<LENGTH; i++)if ((*T)->kind == BRANCH && (*T)->a.bh.ptr[i]) /* 第i个结点不空 */if ((*T)->a.bh.ptr[i]->kind == BRANCH) /* 是子树 */DestroyDSTable(&(*T)->a.bh.ptr[i]);else /* 是叶子 */{free((*T)->a.bh.ptr[i]);(*T)->a.bh.ptr[i] = NULL;}free(*T); /* 释放根结点 */*T = NULL; /* 空指针赋0 */}}int ord(char c){c = toupper(c);if (c >= 'A'&&c <= 'Z')return c - 'A' + 1; /* 英文字母返回其在字母表中的序号 */elsereturn 0; /* 其余字符返回0 */}Record *SearchTrie(TrieTree T, KeysType K){ /* 在键树T中查找关键字等于K的记录。算法9.16 */TrieTree p;int i;for (p = T, i = 0; p&&p->kind == BRANCH&&i<K.num; p = p->a.bh.ptr[ord(K.ch[i])], ++i);/* 对K的每个字符逐个查找,*p为分支结点,ord()求字符在字母表中序号 */if (p&&p->kind == LEAF&&p->a.lf.K.num == K.num&&EQ(p->a.lf.K.ch, K.ch)) /* 查找成功 */return p->a.lf.infoptr;else /* 查找不成功 */return NULL;}void InsertTrie(TrieTree *T, Record *r){ /* 初始条件: Trie键树T存在,r为待插入的数据元素的指针 *//* 操作结果: 若T中不存在其关键字等于(*r).key.ch的数据元素, *//*           则按关键字顺序插r到T中 */TrieTree p, q = NULL, ap;int i = 0, j;KeysType K1, K = r->key;if (!*T) /* 空树 */{*T = (TrieTree)malloc(sizeof(TrieNode));(*T)->kind = BRANCH;for (i = 0; i<LENGTH; i++) /* 指针量赋初值NULL */(*T)->a.bh.ptr[i] = NULL;p = (*T)->a.bh.ptr[ord(K.ch[0])] = (TrieTree)malloc(sizeof(TrieNode));p->kind = LEAF;p->a.lf.K = K;p->a.lf.infoptr = r;}else /* 非空树 */{for (p = *T, i = 0; p&&p->kind == BRANCH&&i<K.num; ++i){q = p;p = p->a.bh.ptr[ord(K.ch[i])];}i--;if (p&&p->kind == LEAF&&p->a.lf.K.num == K.num&&EQ(p->a.lf.K.ch, K.ch)) /* T中存在该关键字 */return;else /* T中不存在该关键字,插入之 */{if (!p) /* 分支空 */{p = q->a.bh.ptr[ord(K.ch[i])] = (TrieTree)malloc(sizeof(TrieNode));p->kind = LEAF;p->a.lf.K = K;p->a.lf.infoptr = r;}else if (p->kind == LEAF) /* 有不完全相同的叶子 */{K1 = p->a.lf.K;do{ap = q->a.bh.ptr[ord(K.ch[i])] = (TrieTree)malloc(sizeof(TrieNode));ap->kind = BRANCH;for (j = 0; j<LENGTH; j++) /* 指针量赋初值NULL */ap->a.bh.ptr[j] = NULL;q = ap;i++;} while (ord(K.ch[i]) == ord(K1.ch[i]));q->a.bh.ptr[ord(K1.ch[i])] = p;p = q->a.bh.ptr[ord(K.ch[i])] = (TrieTree)malloc(sizeof(TrieNode));p->kind = LEAF;p->a.lf.K = K;p->a.lf.infoptr = r;}}}}void TraverseDSTable(TrieTree T, Status(*Vi)(Record*)){ /* 初始条件: Trie键树T存在,Vi是对记录指针操作的应用函数 *//* 操作结果: 按关键字的顺序输出关键字及其对应的记录 */TrieTree p;int i;if (T){for (i = 0; i<LENGTH; i++){p = T->a.bh.ptr[i];if (p&&p->kind == LEAF)Vi(p->a.lf.infoptr);else if (p&&p->kind == BRANCH)TraverseDSTable(p, Vi);}}}

#include "TrieTree.h"Status pr(Record *r){printf("(%s,%d)", r->key.ch, r->others.ord);return OK;}void main(){TrieTree t;int i;char s[MAXKEYLEN + 1];KeysType k;Record *p;Record r[N] = { { { "CAI" }, 1 }, { { "CAO" }, 2 }, { { "LI" }, 3 }, { { "LAN" }, 4 },{ { "CHA" }, 5 }, { { "CHANG" }, 6 }, { { "WEN" }, 7 }, { { "CHAO" }, 8 },{ { "YUN" }, 9 }, { { "YANG" }, 10 }, { { "LONG" }, 11 }, { { "WANG" }, 12 },{ { "ZHAO" }, 13 }, { { "LIU" }, 14 }, { { "WU" }, 15 }, { { "CHEN" }, 16 } };/* 数据元素(以教科书式9-24为例) */InitDSTable(&t);for (i = 0; i<N; i++){r[i].key.num = strlen(r[i].key.ch) + 1;r[i].key.ch[r[i].key.num] = Nil; /* 在关键字符串最后加结束符 */p = SearchTrie(t, r[i].key);if (!p)InsertTrie(&t, &r[i]);}printf("按关键字符串的顺序遍历Trie树(键树):\n");TraverseDSTable(t, pr);printf("\n请输入待查找记录的关键字符串: ");scanf("%s", s);k.num = strlen(s) + 1;strcpy(k.ch, s);k.ch[k.num] = Nil; /* 在关键字符串最后加结束符 */p = SearchTrie(t, k);if (p)pr(p);elseprintf("没找到");printf("\n");DestroyDSTable(&t);}

哈弗曼编码

/* c1.h (程序名) */#include<string.h>#include<ctype.h>#include<malloc.h> /* malloc()等 */#include<limits.h> /* INT_MAX等 */#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<stdlib.h> /* atoi() */#include<io.h> /* eof() */#include<math.h> /* floor(),ceil(),abs() */#include<process.h> /* exit() *//* 函数结果状态代码 */#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASIBLE -1/* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */typedef int ElemType;typedef struct{unsigned int weight;unsigned int parent, lchild, rchild;}HTNode, *HuffmanTree; /* 动态分配数组存储赫夫曼树 */typedef char **HuffmanCode; /* 动态分配数组存储赫夫曼编码表 */

#include "HuffmanTree.h"int min1(HuffmanTree t, int i){ /* 函数void select()调用 */int j, flag;unsigned int k = UINT_MAX; /* 取k为不小于可能的值 */for (j = 1; j <= i; j++)if (t[j].weight<k&&t[j].parent == 0)k = t[j].weight, flag = j;t[flag].parent = 1;return flag;}void select(HuffmanTree t, int i, int *s1, int *s2){ /* s1为最小的两个值中序号小的那个 */int j;*s1 = min1(t, i);*s2 = min1(t, i);if (*s1>*s2){j = *s1;*s1 = *s2;*s2 = j;}}void HuffmanCoding(HuffmanTree *HT, HuffmanCode *HC, int *w, int n) /* 算法6.12 */{ /* w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC */int m, i, s1, s2, start;unsigned c, f;HuffmanTree p;char *cd;if (n <= 1)return;m = 2 * n - 1;*HT = (HuffmanTree)malloc((m + 1)*sizeof(HTNode)); /* 0号单元未用 */for (p = *HT + 1, i = 1; i <= n; ++i, ++p, ++w){(*p).weight = *w;(*p).parent = 0;(*p).lchild = 0;(*p).rchild = 0;}for (; i <= m; ++i, ++p)(*p).parent = 0;for (i = n + 1; i <= m; ++i) /* 建赫夫曼树 */{ /* 在HT[1~i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2 */select(*HT, i - 1, &s1, &s2);(*HT)[s1].parent = (*HT)[s2].parent = i;(*HT)[i].lchild = s1;(*HT)[i].rchild = s2;(*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight;}/* 从叶子到根逆向求每个字符的赫夫曼编码 */*HC = (HuffmanCode)malloc((n + 1)*sizeof(char*));/* 分配n个字符编码的头指针向量([0]不用) */cd = (char*)malloc(n*sizeof(char)); /* 分配求编码的工作空间 */cd[n - 1] = '\0'; /* 编码结束符 */for (i = 1; i <= n; i++){ /* 逐个字符求赫夫曼编码 */start = n - 1; /* 编码结束符位置 */for (c = i, f = (*HT)[i].parent; f != 0; c = f, f = (*HT)[f].parent)/* 从叶子到根逆向求编码 */if ((*HT)[f].lchild == c)cd[--start] = '0';elsecd[--start] = '1';(*HC)[i] = (char*)malloc((n - start)*sizeof(char));/* 为第i个字符编码分配空间 */strcpy((*HC)[i], &cd[start]); /* 从cd复制编码(串)到HC */}free(cd); /* 释放工作空间 */}void main(){HuffmanTree HT;HuffmanCode HC;int *w, n, i;printf("请输入权值的个数(>1):");scanf("%d", &n);w = (int*)malloc(n*sizeof(int));printf("请依次输入%d个权值(整型):\n", n);for (i = 0; i <= n - 1; i++)scanf("%d", w + i);HuffmanCoding(&HT, &HC, w, n);for (i = 1; i <= n; i++)puts(HC[i]);}

#include "HuffmanTree.h"int min1(HuffmanTree t, int i){ /* 函数void select()调用 */int j, flag;unsigned int k = UINT_MAX; /* 取k为不小于可能的值 */for (j = 1; j <= i; j++)if (t[j].weight<k&&t[j].parent == 0)k = t[j].weight, flag = j;t[flag].parent = 1;return flag;}void select(HuffmanTree t, int i, int *s1, int *s2){ /* s1为最小的两个值中序号小的那个 */int j;*s1 = min1(t, i);*s2 = min1(t, i);if (*s1>*s2){j = *s1;*s1 = *s2;*s2 = j;}} /* 以上同algo6-1.c */void HuffmanCoding(HuffmanTree *HT, HuffmanCode *HC, int *w, int n) /* 前半部分为算法6.12 */{ /* w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC */int m, i, s1, s2; /* 此句与algo6-1.c不同 */unsigned c, cdlen; /* 此句与algo6-1.c不同 */HuffmanTree p;char *cd;if (n <= 1)return;m = 2 * n - 1;*HT = (HuffmanTree)malloc((m + 1)*sizeof(HTNode)); /* 0号单元未用 */for (p = *HT + 1, i = 1; i <= n; ++i, ++p, ++w){(*p).weight = *w;(*p).parent = 0;(*p).lchild = 0;(*p).rchild = 0;}for (; i <= m; ++i, ++p)(*p).parent = 0;for (i = n + 1; i <= m; ++i) /* 建赫夫曼树 */{ /* 在HT[1~i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2 */select(*HT, i - 1, &s1, &s2);(*HT)[s1].parent = (*HT)[s2].parent = i;(*HT)[i].lchild = s1;(*HT)[i].rchild = s2;(*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight;}/* 以下为算法6.13,无栈非递归遍历赫夫曼树,求赫夫曼编码,以上同算法6.12 */*HC = (HuffmanCode)malloc((n + 1)*sizeof(char*));/* 分配n个字符编码的头指针向量([0]不用) */cd = (char*)malloc(n*sizeof(char)); /* 分配求编码的工作空间 */c = m;cdlen = 0;for (i = 1; i <= m; ++i)(*HT)[i].weight = 0; /* 遍历赫夫曼树时用作结点状态标志 */while (c){if ((*HT)[c].weight == 0){ /* 向左 */(*HT)[c].weight = 1;if ((*HT)[c].lchild != 0){c = (*HT)[c].lchild;cd[cdlen++] = '0';}else if ((*HT)[c].rchild == 0){ /* 登记叶子结点的字符的编码 */(*HC)[c] = (char *)malloc((cdlen + 1)*sizeof(char));cd[cdlen] = '\0';strcpy((*HC)[c], cd); /* 复制编码(串) */}}else if ((*HT)[c].weight == 1){ /* 向右 */(*HT)[c].weight = 2;if ((*HT)[c].rchild != 0){c = (*HT)[c].rchild;cd[cdlen++] = '1';}}else{ /* HT[c].weight==2,退回 */(*HT)[c].weight = 0;c = (*HT)[c].parent;--cdlen; /* 退到父结点,编码长度减1 */}}free(cd);}void main(){ /* 主程序同algo6-1.c */HuffmanTree HT;HuffmanCode HC;int *w, n, i;printf("请输入权值的个数(>1):");scanf("%d", &n);w = (int *)malloc(n*sizeof(int));printf("请依次输入%d个权值(整型):\n", n);for (i = 0; i <= n - 1; i++)scanf("%d", w + i);HuffmanCoding(&HT, &HC, w, n);for (i = 1; i <= n; i++)puts(HC[i]);}




0 0
原创粉丝点击