树的应用

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;
	else
		return 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;
	}
	else
		return 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);
	else
		return 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); /* 在左子树中继续查找 */
	else
		SearchBST1(&(*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为左孩子 */
		else
			p->rchild = s; /* 被插结点*s为右孩子 */
		return TRUE;
	}
	else
		return 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的右子树 */
		else
			q->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);
		else
			DeleteBST(&(*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");
	}
	else
		printf("表中不存在此值\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;
}
//
//wrong
void 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);
	else
		return 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);
	else
		printf("表中不存在此值");
	printf("\n");
	//wrong
	DestroyDSTable(&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);
	else
		printf("没找到");
	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;
	}
	else
		return 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);
	else
		printf("没找到");
	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; /* 英文字母返回其在字母表中的序号 */
	else
		return 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);
	else
		printf("没找到");
	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';
		else
			cd[--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]);
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值