一、树
1、树的定义
树是一种非线性的数据结构,是递归的。
2、树的基本术语
①结点的度:结点拥有子树的个数或者分支的个数。例如,A结点有3棵子树,A结点的度为3。
②树的度:树中结点度的最大值。
③叶子结点:树中结点度为0的结点。
④森林:互不相交的树的集合。
二、二叉树
1、定义
①每个结点至多有两个子树;
②二叉树是有序树,左右子树不能颠倒。
2、性质
①在二叉树第i层上有2^(i-1)个结点
②深度为k的二叉树至多有2^k--1个结点
③非空二叉树上叶子结点数等于双分支结点数加1
④具有n个结点的完全二叉树的深度为log2(n)取下界+1
3、二叉树的存储结构
1、链式存储结构
typedef struct BTNode{
char data; //结点数据
struct BTNode *lchild; //左孩子结点
struct BTNode *rchild;
};
4、二叉树的遍历
1、先序遍历递归
void preorder(BTNode *p){
if(p!=NULL){
cout<<p->data;
preorder(p->lchild);
preorder(p->rchild);
}
}
例题:在一棵二叉链表为存储结构的二叉树中,查找data值等于key的结点是否存在。存在返回1,否则返回0.
int search(BTNode *p,int key){
if(p!=NULL){
if(p->data == NULL) return 0;
if(p->data == key) //先序遍历查找
return 1;
else{
search(p->lchild,key);
search(p->rchild,key);
}
}
}
2、中序遍历
void inorder(BTNode *p){
if(p!=NULL){
inorder(p->lchild);
cout<<p->data;
inorder(p->rchild);
}
}
例题:中序遍历第k个结点的值(二叉链表存储)
void trave(BTNode *p,int k){
if(p!=NULL){
trave(p->lchild,k);
++n;
if(n==k){
cout<<p->data;
return ;
}
trave(p->rchild,k);
}
}
3、后序遍历
void postorder(BTNode *p){
if(p!=NULL){
postorder(p->lchild);
postorder(p->rchild);
cout<<p->data;
}
}
例题:表达式(a-(b+c))*(d/e)求表达式的值
int comp(BTNode *p){
int a,b;
if(p!=NULL){
if(p->lchild!=NULL && p->rchild!=NULL){
a = comp(p->lchild);
b = comp(p->rchild);
return op(a,b,p->data);
}
else return p->data-'0';
}else{
return 0;
}
}
int op(int op_left,int op_right,char c){
if(c == '+')
return op_left+op_right;
if(c == '-')
return op_left-op_right;
if(c == '*')
return op_left*op_right;
if(c == '/')
return op_left/op_right;
return 0;
}
例题2:求二叉树的高度(左子树或者右子树的最大值)
int getDepth(BTNode *p){
if(p==NULL) return 0;
int leftTree,rightTree;
leftTree = getDepth(p->lchild);
rightTree = getDepth(p->rchild);
return (leftTree > rightTree?leftTree:rightTree) +1; //最大值加1因为从0开始
}
4、层序遍历
int level(BTNode *p){
//定义一个循环队列
BTNode *que[maxSize];
int front,rear;
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];
cout<<q->data;
if(q->lchild!=NULL){
rear = (rear+1)%maxSize;
que[rear] = q->lchild;
}
if(q->rchild!=NULL){
rear = (rear+1)%maxSize;
que[rear] = q->rchild;
}
}
}
}
例题:求二叉树的宽度(具有结点数最多的那一层上的结点个数)
typedef struct{
BTNode *p;
int lno; //层号
}Wt;
int maxNode(BTNode *b{
//定义一个循环队列
Wt que[maxSize];
int front,rear;
front = rear =0;
int Lno=0;
BTNode *q;
if(b!=NULL){
rear = (rear+1)%maxSize;
que[rear].p = b;
que[rear].lno = 1;
while(front!=rear){
front = (front+1)%maxSize;
q = que[front].p;
Lno = que[front].lno;
if(q->lchild!=NULL){
rear = (rear+1)%maxSize;
que[rear].p = q->lchild;
que[rear].lno = Lno+1;
}
if(q->rchild!=NULL){
rear = (rear+1)%maxSize;
que[rear].p = q->rchild;
que[rear].lno = Lno+1;
}
}
//得出最大层Lno;
int max = 0;
int n;
for(int i=0;i<Lno;i++){
n=0;
for(int j=0;j<rear;j++){
if(que[j].lno == i)
n++;
if(max<n)
max = n;
}
}
return max;
}
}
二叉树深度优先遍历
其实就是先中后序遍历的非递归
//先序遍历非递归
void preorderNonrecursion(BTNode *bt){
if(bt!=NULL){
//定义一个栈
BTNode *stack[maxSize];
int top = -1;
BTNode *p;
stack[++top] = bt;
while(top!=-1){
p = stack[top--];
cout<<p->data;
if(p->rchild!=NULL){ //注意先右子树后左子树
stack[++top] = p->rchild;
}
if(p->lchild!=NULL){
stack[++top] = p->lchild;
}
}
}
}
//后序遍历的非递归就是先序遍历过程中对左右子树交换(逆后序遍历),然后在逆序输出
void postorderNonrecursion(BTNode *bt){
BTNode *stack1[maxSize]; int top1 = -1;
BTNode *stack2[maxSize]; int top2 = -1;
BTNode *p;
stack1[++top1] = bt;
while(top1!=-1){
p = stack[top1--];
stack2[++top2] = p;
if(p->lchild!=NULL){
stack2[++top2] = p->lchild;
}
if(p->rchild!=NULL){
stack2[++top2] = p->rchild;
}
}
while(top2!=-1)
{
p = stack2[top2--];
cout<<p->data;
}
}
//中序遍历非递归
void inorderNonrecursion(BTNode *bt){
if(bt!=NULL){
BTNode *stack[maxSize]; int top = -1;
BTNode *p;
p = bt;
while(top!=-1 || p!=NULL){
while(p!=NULL){
stack[++top] = p;
p = p->lchild;
}
if(top!=-1){
p = stack[top--];
cout<<p->data;
p = p->rchild;
}
}
}
}
线索二叉树
二叉树的线索化可以提高遍历的执行效率,线索二叉树可以把栈省略掉。因为线索化后近似于一个线性结构,分支结构的遍历就变成了近似于线性结构的遍历。
//线索二叉树结点定义
typedef struct TBTNode{
char data;
int ltag,rtag;
struct TBTNode *lchild;
struct TBTNode *rchild;
};
//中序线索化 pre 为p的前驱结点,初始为NULL 即TBTNode *pre = NULL;
void createInThread(TBTNode *root){
TBTNode *pre = NULL;
if(root!=NULL){
InThread(root,pre);
pre->rchild = NULL;
pre->rtag = 1;
}
}
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;
InThread(p->rchild,pre);
}
}
//中序线索遍历
//1、以p为根的中序线索二叉树中序序列下的第一个节点
TBTNode *First(TBTNode *p){
while(p->ltag==0)
p = p->lchild;
return p;
}
//2、结点p的后继
TBTNode *Next(TBTNode *p){
if(p->rtag==0)
return First(p->rchild);
else
return p->rchild;
}
//3、遍历
void inorder(TBTNode *root){
TBTNode *p = First(root);
for(p;p!=NULL;p=Next(p)){
cout<<p->data;
}
}