目录
二叉树
二叉树链式存储结构
typedef struct BTNode
{
char data; //数据域
struct BTNode *lchild; //左指针域
struct BTNode *rchild; //右指针域
}BTNode;
先序递归遍历
void preorder(BTNode *p)
{
if(p!=NULL)
{
visit(p); //其中包含了对结点P的各种访问操作
preorder(p->lchild); //先序遍历左子树
preorder(p->rchild); //先序遍历右子树
}
}
中序递归遍历
void inorder(BTNode *p)
{
if(p!=NULL)
{
inorder(p->lchild); //先序遍历左子树
visit(p); //其中包含了对结点P的各种访问操作
inorder(p->rchild); //先序遍历右子树
}
}
后序递归遍历
void postorder(BTNode *p)
{
if(p!=NULL)
{
postorder(p->lchild); //先序遍历左子树
postorder(p->rchild); //先序遍历右子树
visit(p); //其中包含了对结点P的各种访问操作
}
}
层序遍历
void level(BTNode *p)
{
int front,rear;
BTNode *que[maxSize]; //定义循环队列,用来记录将要访问的层次上的结点
front=rear=0;
BTNode *q;
if(p!=NULL)
{
rear=(rear+1)%maxSize;
que[rear]=p; //根结点入队
while(front!=rear) //队列不空时进行循环
{
front=(front+1)%maxSize;
q=que(front); //队头结点出队
visit(q); //访问队头结点
if(q->lchild!=NULL) //如果左子树不空,左子树根结点入队
{
rear=(rear+1)%maxSize;
que[rear]=q->lchild;
}
if(q->rchild!=NULL) //如果右子树不空,右子树根结点入队
{
rear=(rear+1)%maxSize;
que[rear]=q->rchild;
}
}
}
}
void LevelOrder(BiTree T){
InitQueue(Q); //初始化辅助队列
BiTree p;
EnQueue(Q,T); //将根结点入队
while(!IsEmpty(Q)){ //队列不空则循环
DeQueue(Q,p); //队头结点出队
visit(p); //访问出队结点
if(p->lchild != NULL)
EnQueue(Q,p->lchild);
if(p->rchild != NULL)
EnQueue(Q,p->rchild);
}
}
先序非递归遍历
(注意先入右孩子后入左孩子)
void preorderNonrecursion(BTNode *bt)
{
if(bt!=NULL)
{
BTNode *Stack[maxSize]; //定义一个栈
int top=-1; //初始化栈
BTNode *p;
Stack[++top]=bt; //根结点入栈
while(top!=-1) //栈空循环结束
{
p=Stack[top--]; //出栈并输出栈顶结点
visit(p); //访问p结点
if(p->rchild!=NULL) //栈顶结点的右孩子存在,则右孩子入栈
Stack[++top]=p->rchild;
if(p->lchild!=NULL) //栈顶结点的左孩子存在,则左孩子入栈
Stack[++top]=p->lchild;
}
}
}
中序非递归遍历
void inoderNonrecursion(BTNode *bt)
{
if(bt!=NULL)
{
BTNode *Stack[maxSize]; //定义一个栈
int top=-1; //初始化栈
BTNode *p;
p=bt; //从根结点开始遍历
while(top!=-1||p!=NULL) //注意条件为栈非空或p非空
{
while(p!=NULL) //左孩子非空,左孩子持续入栈
{
Stack[++top]=p;
p=p->lchlid;
}
if(top!=-1) //栈非空情况下出栈并输出出栈结点
{
p=Stack[top--];
visit(p); //访问出栈结点
p=p->rchild; //出栈结点右孩子准备入栈
}
}
}
}
后序非递归遍历
(采用的是逆输出 逆后序遍历序列,而逆后序遍历序列 即 将 先序遍历序列左右子树顺序交换)
void postorderNonrecursion(BTNode *bt)
{
if(bt!=NULL)
{
BTNode *Stack1[maxSize];
int top1=-1;
BTNode *Stack2[maxSize];
int top2=-1; //定义并初始化两个栈
BTNode *p=NULL;
Stack1[++top1]=bt; //根结点入栈
while(top1!=-1) //栈非空则循环
{
p=Stack1[top1--];
Stack2[++top2]=p; //注意将前面的出栈换成了入栈2
if(p->lchild!=NULL)
Stack1[++top1]=p->lchild;
if(p->rchild!=NULL)
Stack1[++top1]=p->rchild; //注意与前序遍历比先入左孩子
}
while(top2!=-1)
{
p=Stack2[top2--];
visit(p); //访问p的函数
}
}
}
线索二叉树
线索二叉树结点定义
typedef struct TBTNode
{
char data;
int ltag,rtag; //线索标记
struct TBTNode *lchild; //tag=1,则为前驱,tag=0,则为左孩子
struct TBTNode *rchild; //tag=1,则为前驱,tag=0,则为右孩子
}TBTNode;
中序线索二叉树
二叉树线索化
void InThread(TBTNode *p,TBTNode *&pre)
{
if(p!=NULL)
{
InThread(p->lchild,pre); //递归,左子树线索化
if(p->lchild==NULL) //建立当前结点的前驱结点
{
p->lchild=pre;
p->ltag=1;
}
if(pre!=NULL&&pre->rchild==NULL) //建立前驱结点的后继线索
{
pre->rchild=p;
pre->rtag=1;
}
pre=p; //使p成为下一个结点的前驱结点
InThread(p->rchild,pre); //递归,右子树线索化
}
}
建立中序线索二叉树主程序
void createInThread(TBTNode *root)
{
TBTNode *pre=NULL; //前驱结点指针
if(root!=NULL)
{
InThread(root,pre); //非空二叉树线索化
pre->rchild=NULL;
pre->rtag=1; //处理最后一个结点的后继(线索化过程最后一个节点停在pre上)
}
}
中序线索二叉树找中序序列下第一个结点
TBTNode *First(TBTNode *p)
{
while(p->ltag==0)
p=p->lchild; //最左下结点(不一定是叶节点)
return p;
}
结点p在中序下的后继结点
TBTNode *Next(TBTNode *p)
{
if(p->rtag==0)
return First(p->rchild); //无线索,找右孩子的最左下结点(即前一步所求的中序下一结点)
else
return p->rchild; //直接返回后继线索
中序线索二叉树上执行中序遍历的算法
void Inorder(TBTNode *root)
{
for(TBTNode *p=First(root);p!=NULL;p=Next(p))
visit(p); //访问结点p
}
前序线索二叉树
二叉树线索化
void preThread(TBTNode *p,TBTNode *&pre)
{
if(p!=NULL)
{
if(p->lchild==NULL) //建立当前结点的前驱结点
{
p->lchild=pre;
p->ltag=1;
}
if(pre!=NULL&&pre->rchild==NULL) //建立前驱结点的后继线索
{
pre->rchild=p;
pre->rtag=1;
}
pre=p; //使p成为下一个结点的前驱结点
//注意这里只有左右指针不是线索才需要递归
if(p->ltag==0)
preThread(p->lchild,pre); //递归,左子树线索化
if(p->rtag==0)
preThread(p->rchild,pre); //递归,右子树线索化
}
}
执行前序遍历
void preorder(TBTNode *root)
{
if(root!=NULL)
{
TBTNode *p=root;
while(p!=NULL)
{
while(p->ltag==0) //左指针不是线索时,边访问边左移
{
visit(p);
p=p->lchild;
}
visit(p); //p的左指针为线索,但还未访问
p=p->rchild; //无论是否为线索都指向其后继
}
}
}
后序线索二叉树
void postThread(TBTNode *p,TBTNode *&pre)
{
if(p!=NULL)
{
preThread(p->lchild,pre); //递归,左子树线索化
preThread(p->rchild,pre); //递归,右子树线索化
if(p->lchild==NULL) //建立当前结点的前驱结点
{
p->lchild=pre;
p->ltag=1;
}
if(pre!=NULL&&pre->rchild==NULL) //建立前驱结点的后继线索
{
pre->rchild=p;
pre->rtag=1;
}
pre=p; //使p成为下一个结点的前驱结点
}
}
二叉排序树
存储结构
typedef struct BTNode
{
int key; // 关键字
struct BTNode *lchild; // 左指针域
struct BTNode *rchild; // 右指针域
}BTNode;
查找关键字
BTNode* BSTSearch(BTNode* bt, int key)
{
if (bt == NULL)
return NULL; // 来到空指针域,查找不成功返回NULL
else
{
if (key == bt->key) // 查找成功,返回关键字所在结点指针
return bt;
else if (key < bt->key) // 小于根结点关键字前往左子树
return BSTSearch(bt->lchild, key); //该查找函数有返回值,所以递归调用时要用return
else // 大于根结点关键字前往左子树
return BSTSearch(bt->rchild, key);
}
}
插入关键字
int BSTInsert(BTNode *&bt, int key) // 指针bt要改变,所以用引用型指针
{
if (bt == NULL) //原本为空,即创建新树
{
bt = new BTNode; // 创建新结点
// bt = (BTNode*)malloc(sizeof(BTNode));
bt->lchild = bt->rchild = NULL; // 将子树赋空
bt->key = key; //将值插入
return 1; // 插入成功,返回1
}
else
{
if (key == bt->key) // 关键字已存在于树中,插入失败,返回0
return 0;
else if (key < bt->key)
return BSTInsert(bt->lchild, key);
else
return BSTInsert(bt->rchild, key);
}
}
二叉排序树的构造
void CreateBST(BTNode *&bt, int key[], int n)
{
int i;
bt = NULL; // 将树清空
for (int i = 0;i < n; ++i) // 调用插入函数,逐个插入关键字
BSTInsert(bt, key[i]);
}
删除关键字
void DeleteBTS(BTNode *&bt, int key)
{
if (bt == NULL) // 关键字不存在树中,删除失败,返回0
return 0;
else
{
if (key == bt->key) // 找到关键字,执行删除函数
return Delete(bt);
else if (key < bt->key)
return DeleteBTS(bt->lchild, key);
else
return DeleteBTS(bt->rchild, key);
}
}
void Delete(BTNode *&bt)
{
if (bt->lchild != NULL && bt->rchild == NULL) // 右子树为空
{
BTNode* q = bt;
bt = bt->lchild; //用右孩子填补
delete(q);
}
else if (bt->lchild == NULL && bt->rchild != NULL) // 左子树为空
{
BTNode* q = bt;
bt = bt->rchild; //用左孩子填补
delete(q);
}
else // 左右子树均不为空
{
BTNode* q = bt;
BTNode* s = bt->lchild;
while (s->rchild != NULL) //先转向左孩子,然后找最右结点,即为中序遍历下bt的直接前驱
{
q = s; // q记录的是s的双亲结点
s = s->rchild;
}
bt->data = s->data; // 用直接前驱的关键值替换bt
if (q != bt) // 若双亲不是待删除结点
q->rchild = s->lchild; //s是最右结点,要么有左孩子要么没有左孩子
//删除s后q会空出右指针域,将s的左孩子或NULL给q的右指针域
else // 若双亲就是待删除结点,相当于s为其左孩子也为其直接前驱
q->lchild = s->lchild; //删除s后q会空出左指针域,将s的左孩子或NULL给q的左指针域
delete(s);
}
}
哈夫曼树
存储结构
typedef struct{
unsigned int weight;
unsigned int parent,lchild,rchild;
}HTNode, *HuffmanTree;
对各字符的哈夫曼编码程序如下
typedef char **HuffmanCode; //动态二维数组存储哈夫曼编码
void HuffmanCoding(HuffmanTree HT,Huffmancode &HC,int n) //从叶子到根逆向求编码,存储在HC中
{
HC=new char*[n+1]; //为了方便实现,从1号单元开始使用
cd=new char[n]; //存放结点哈夫曼编码的字符串数组
cd[n-1]= '\0'; //字符串结束符
for(int i=1;i<=n;i++) //从叶子结点出发,得到的哈夫曼编码是逆序的,在字符串数组里逆序存放
{
int start=n-1;
int c=i; //当前结点在数组中的位置
int p=HT[i].parent; //当前结点的父节点在数组中的位置
while(p!=0) //一直寻找到根结点
{
--start; //回溯一次,start向前一位
if(HT[p].lchild==c) //如果该结点为左孩子,则对应字符编码“0”
cd[start]='0';
else //如果该结点为右孩子,则对应字符编码“1”
cd[start]='1';
c=p; //以父结点为孩子结点,继续朝树根方向遍历
p=HT[p].parent;
}
HC[i]=new char[n-start]; //跳出循环后为第i个字符编码分配空间
strcpy(HC[i],&cd[start]); //cd数组中从下标start开始,存放的即为哈夫曼编码
}
delete(cd); //释放临时空间
}
读入二进制流的哈夫曼编码
void ReadHaffmanTree(char s[],Bitree T)
{
int len=strlen(s);
int i=0;
Bitree now = T;
while(i++<len)
{
if(now->left==NULL&&now->right==NULL) //叶子结点
{
count<<now->data<<"";
now = T;
continue;
}
if(s[i]=='0')
{
if(now->left=NULL) //没有左孩子了
{
printf(“编码错误”);
return 1;
}
else
now=now->left;
}
else if(s[i]=='1')
{
if(now->right==NULL) //没有右孩子了
{
printf(“编码错误”);
return 1;
}
else
now=now->right;
}
}
}
译码过程
void HuffmanTreeDeCoding(char string){
char a;
BiTree p = T;
while((a=getchar())!='\n'&&a!=EOF){
if(a=='0')
p=p->left;
else if(a=='1')
p=p->right;
if(p->kind==leaf){
printf("%c",p->x);
p=T;
}
}
return 0;
}