【数据结构】树
发布时间:2020-12-15 05:59:37 所属栏目:安全 来源:网络整理
导读:1、树的定义 树(Tree)是n个结点(元素的有限集合)。当n=0时,称这棵树为空树。在非空树T中: (1) 有且只有一个特殊的结点称为树的根结点(root),根结点没有前驱结点。 (2) 当n1时,除了根结点之外的其余的结点又被分成m个互不相交的子集。每个子集
1、树的定义(1)有且只有一个特殊的结点称为树的根结点(root),根结点没有前驱结点。 (2)当n>1时,除了根结点之外的其余的结点又被分成m个互不相交的子集。每个子集本身又是一棵树,这些树称为根结点的子树。 2、相关的术语(1)结点的度、树的度 结点的度:结点所拥有所有子树的个数; 树的度:树中各结点度的最大值。 (2)叶子结点、分支结点 叶子结点:度为0的结点称为叶子结点; 分支结点:度不为0的结点称为分支结点。 (3)孩子、兄弟、双亲 孩子:树中一个结点的子树的根结点称为这个结点的孩子; 双亲:上述说法相应的称为双亲; 兄弟:具有同一个双亲的孩子结点互称兄弟。 (4)祖先、子孙 一个结点的所有子树中的结点称之为该节点的子孙结点,结点的祖先是从根结点 到该结点所经分支上的所有结点。 (5)结点的层数、树的深度 树既是一种递归结构也是一个层次结构,树中的每一个结点都处在一定的层次上。 树的深度:树中所有最大结点的最大层数称为树的深度。 (6)堂兄弟 双亲在同一层的结点互为堂兄弟。 (7)有序树、无序树 如果一棵树中结点的各个子树从左到右是有次序的,即若交换了某个结点各 子树的相对位置则构成不同的树,称这棵树为有序树。 反之,则称为无序树。 (7)森林 m(m>0)棵不相交的树的集合称为森林。自然界中树和森林是不同的概念。 但是在数据结构中,任何一棵树,删去根节点就变成森林了。
3、树的抽象数据类型ADT Tree
{
Data:
树是由一个根结点和若干棵子树构成的.
树中结点具有相同数据类型及层次结构.
Operation:
//操作结果:构造一棵空树
InitTree(&T)
//初始条件:串S是以广义表形式表示的树
//操作结果:按照S构造一棵树
CreateTree(&T,S)
//初始条件:树T存在,Visit是对结点操作的应用函数
//操作结果:按某种次序对T的每个结点调用函数Visit()
//一次且至多一次,一旦visit()失败,则操作失败.
OrderTree(T,Visit())
//初始条件:树T存在
//操作结果:在树T中查找元素e,若查找成功,返回true
//否则返回false
SearchTree(T,&e)
//初始条件:树T存在
//操作结果:以某种形式输出树T
PrintTree(T)
//初始条件:树T存在
//操作结果:求树T的深度
TreeDepth(T)
//初始条件:树T存在
//操作结果:销毁树T
DestroyTree(&T)
}
4、树的存储结构树中节点之间的逻辑关系都是父子关系,即通过双亲和孩子来刻画结点之间的逻辑关系,因而树的存储结构要求不仅存储各结点的数据信息,还要唯一地反映树中各结点之间的逻辑关系--父子关系,其关键是如何表示结点的双亲和孩子。根据结点中指针域所指的对象可分为双亲表示方法,孩子表示法和双亲孩子表示法。
(1)双亲表示法a>数组表示#define MAX_TREE_SIZE 100 //树中结点的最大个数
typedef struct
{
TElemType data; //结点的值
int parent; //结点的双亲在数组中的下标
}pTreeNode; //结点类型
pTreeNode pTree[MAX_TREE_SIZE];
b>链表表示因为树中除了根节点以外,每一个结点只有一个双亲,所以这种表示方法得到的结果是一个单链表#define MAX_TREE_SIZE 100 //树中结点的最大个数
typedef struct
{
TElemType data; //结点的值
pTreeNode *parent; //结点的双亲指针
}pTreeNode; //结点类型
(2)孩子表示法a>数组表示#define MAX_SON_SIZE 3 //树的度
typedef struct
{
TElemType data; //结点的值
int Child[MAX_SON_SIZE]; //结点的孩子在数组中的下标
}CTreeNode; //数组元素类型
CTreeNode CTree[MAX_TREE_SIZE];
b>链表表示typedef struct CTNode
{
TElemType data; //结点的值
struct CTNode *child[MAX_SON_SIZE]; //结点的指针域,指向孩子结点
}CTNode,*CTree; //结点的类型
c>左孩子右兄弟表示法typedef struct LRTNode
{
TElemType data; //结点的值
struct LRTNode *lchild; //左孩子指针
struct LRTNode *rsibling; //右兄弟指针
}LRTNode,*LRTree; //结点的类型
(3)双亲孩子表示法a>数组表示typedef struct
{
TElemType data; //结点的值
int parent; //结点的双亲在数组中的下标
int child[MAX_SON_SIZE]; //结点的孩子在数组中的下标
}PCTreeNode; //数组元素的类型
b>链表表示法typedef struct pCTNode
{
TElemType data; //结点的值
struct pCTNode *parent; //结点的双亲指针
struct pCTNode *child[MAX_SON_SIZE];//结点的孩子指针
}PCTNode,*pCTree; //结点类型
c>双亲数组孩子链表表示法typedef struct Node
{
int child; //孩子结点在数组中的下标
struct Node *next; //孩子链表中的结点类型
}CNode;
typedef struct
{
TElemType data; //结点的值
int parent; //结点的双亲在数组中的下标
CNode *Childlink; //指向孩子链表
}PCLink; //数组元素的类型
5、树的基本操作实现孩子链表表示法: typedef struct CTNode
{
TElemType data; //结点的值
struct CTNode *child[MAX_SON_SIZE]; //结点的指针域,指向孩子结点
}CTNode,*CTree; //结点的类型
(1)初始化操作void InitTree(CTree &T)
{
T = NULL;
}
(2)创建树操作创建一棵树就是要在内存中存储一个树的结构。用孩子链表表示方法中就是在内存中生成一个孩子链表。因为树是一种层次结构,创建树的操作首先需要确定输入树的方法,然后再写出相应的算法。不同的输入方法,树的创建方法也不相同。如果采用广义表的形式进行输入: 使用广义表表示一棵树:A(B(D,E(H,I),F),D(G)) 实现代码: void CreateTree(CTree &T,char *S)
{
CTree stack[MS],p;
int i=0,d[MS];
int top = -1;
while (S[i])
{
switch(S[i])
{
case ' ': break;
case '('://??
top++;
stack[top] = p;
d[top] = 0;
break;
case ')'://??
top--;
break;
case ',':
d[top]++;
break;
default:
if (!(p=(CTree)malloc(sizeof(CTNode))))
exit(1);
p->data = S[i];
for (int i = 0;i < MAX_SON_SIZE;i++)
p->child[i] = NULL;
if (!T)
T = p;
else
stack[top]->child[d[top]] = p;
break;
}
i++;
}
}
(3)树的遍历a 前序遍历先访问根节点,然后从左到右依次先序遍历每一个子树,此遍历过程是一个递归的过程。对上图进行前序遍历得到的结果是: A B D E H I F C G
|
