@yanglt7
2018-10-21T15:50:02.000000Z
字数 6736
阅读 763
数据结构和算法
Tips:
如果想要知道某结点的孩子,需要遍历整个树结构。
代码实现
//树的双亲表示法结点结构定义
#define MAX_TREE_SIZE 100
typedef int ElemType;
typedef struct PTNode
{
ElemType data; //结点数据
int parent; //双亲位置
}PTNode;
typedef struct
{
PTNode nodes[MAX_TREE_SIZE];
int r; //根的位置
int n; //结点数目
}PTree;
#define MAX_TREE_SIZE 100
typedef char ElemType;
//孩子结点
typedef struct CTNode
{
int child; //孩子结点的下标
struct CTNode *next; //指向下一个孩子结点的指针
} *ChildPtr;
//表头结构
typedef struct
{
ElemType data; //存放在树中的结点的数据
int parent; //存放双亲的下标
ChildPtr firstchild; //指向第一个孩子的指针
} CTBox;
//树结构
typedef struct
{
CTBox nodes[MAX_TREE_SIZE]; //结点数组
int r,n;
};
拥有三个结点的普通树只有两种情况:两层或者三层。但对于二叉树来说,由于要区分左右,所以就演变成五种形态。
斜树
满二叉树
元素 | A | B | C | D | E | F | ^ |
---|---|---|---|---|---|---|---|
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
lchild | data | rchild |
---|
- 结构定义代码
typedef struct BiTNode
{
ElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再前序遍历右子树。
遍历的顺序为:ABDHIEJCFKG
若二叉树为空,则空操作返回,否则先中序遍历左子树,然后访问根结点,再中序遍历右子树。
遍历的顺序为:HDIBEJAFKCG
若树为空,则空操作返回,否则先从左到右先叶子后结点的方式遍历左右子树,最后访问根结点。
遍历的顺序为:HIDJEBKFGCA
题目要求:建立二叉树并输出每个字符所在的层数。如右图要求输出
代码实现
//前序遍历
#include <stdio.h>
#include <stdlib.h>
typedef char ElemType;
typedef struct BiTNode
{
char data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
//创建一棵二叉树,约定用户遵照前序遍历的方式输入数据
CreateBiTree(BiTree *T)
{
char c;
scanf("%c", &c);
if( ' ' == c )
{
*T = NULL;
}
else
{
*T = (BiTNode *)malloc(sizeof(BiTNode));
(*T)->data = c;
CreateBiTree(&(*T)->lchild);
CreateBiTree(&(*T)->rchild);
}
}
//访问二叉树结点的具体操作
visit(char c, int level)
{
printf("%c 位于第 %d 层\n", c, level);
}
//前序遍历二叉树
PreOrderTraverse(BiTree T, int level)
{
if( T )
{
visit(T->data, level);
PreOrderTraverse(T->lchild, level+1);
PreOrderTraverse(T->rchild, level+1);
}
}
int main()
{
int level = 1;
BiTree T = NULL;
CreateBiTree(&T);
PreOrderTraverse(T, level);
return 0;
}
lchild | ltag | data | rtag | rchild |
---|
- ltag为0时指向该结点的左孩子,为1时指向该结点的前驱
- rtag为0时指向该结点的右孩子,为1时指向该结点的后继
#include <stdio.h>
#include <stdlib.h>
typedef char ElemType;
//线索存储标志位
//Link(0):表示指向左右孩子的指针
//Thread(1):表示指向前驱后继的线索
typedef enum {Link, Thread} PointerTag;
typedef struct BiThrNode
{
char data;
struct BiThrNode *lchild, *rchild;
PointerTag ltag;
PointerTag rtag;
} BiThrNode, *BiThrTree;
//全局变量,始终指向刚刚访问过的结点
BiThrTree pre;
//创建一棵二叉树,约定用户遵照前序遍历的方式输入数据
void CreateBiThrTree(BiThrTree *T)
{
char c;
scanf("%c", &c);
if( ' ' == c )
{
*T = NULL;
}
else
{
*T = (BiThrNode *)malloc(sizeof(BiThrNode));
(*T)->data = c;
(*T)->ltag = Link;
(*T)->rtag = Link;
CreateBiThrTree(&(*T)->lchild);
CreateBiThrTree(&(*T)->rchild);
}
}
//中序遍历线索化
void InThreading(BiThrTree T)
{
if( T )
{
InThreading( T->lchild ); //递归左孩子线索化
//结点处理
//如果该结点没有左孩子,设置ltag为Thread,并把lchild指向刚刚访问的结点
if( !T->lchild )
{
T->ltag = Thread;
T->lchild = pre;
}
if( !pre->rchild )
{
pre->rtag = Thread;
pre->rchild = T;
}
pre = T;
InThreading( T->rchild ); //递归右孩子线索化
}
}
void InOrderThreading( BiThrTree *p, BiThrTree T )
{
*p = (BiThrTree)malloc(sizeof(BiThrNode));
(*p)->ltag = Link;
(*p)->rtag = Thread;
(*p)->rchild = *p;
if( !T )
{
(*p)->lchild = *p;
}
else
{
(*p)->lchild = T;
pre = *p;
InThreading( T );
pre->rchild = *p;
pre->rtag = Thread;
(*p)->rchild = pre;
}
}
void visit( char c )
{
printf("%c", c );
}
//中序遍历二叉树,非递归
void InOrderTraverse( BiThrTree T )
{
BiThrTree p;
p = T->lchild;
while( p != T )
{
while( p->ltag == Link )
{
p = p->lchild;
}
visit( p->data );
while( p->rtag == Thread && p->rchild != T )
{
p = p->rchild;
visit(p->data);
}
p = p->rchild;
}
}
int main()
{
BiThrTree P, T = NULL;
CreateBiThrTree( &T );
InOrderThreading( &P, T );
printf("中序遍历输出结果为: \n");
InOrderTraverse( P );
return 0;
}
后根遍历:先依次遍历每棵子树,然后再访问根结点
先根遍历结果:ABEFCGDHIJ
森林的遍历也分为前序遍历和后序遍历,其实就是按照树的先根遍历和后根遍历依次访问森林的每一棵树
树、森林的前根(序)遍历和二叉树的前序遍历结果相同
先把二叉树简化成叶子结点带权的二叉树(注:树结点间的连线相关的数叫做权,Weight)
结点的路径长度:
树的路径长度:
结点带权路径长度:
树的带权路径长度:
WPL的值越小,说明构造出来的二叉树性能越优