为了立项——二叉树

一、知识点

1.树形结构  :  结构定义+结构操作

根节点是全集(必须先从根开始解决)        节点是集合(事件)        边是关系(指向关系)

       (链表是树的特例,指针域的元素个数)

树的(深度:从上向下)        (高度:从下向上)

节点的深度和高度          节点的度(带了几个子孩子)         节点数量=变数+1

节点的度:一个节点含有的子树的个数,叫做该节点的度


叶节点和终端节点:度为零的节点


双亲结点或父节点:C为G的父节点


孩子节点或子节点:G为C的子节点


兄弟节点:拥有相同父节点的节点称为兄弟节点


树的度:一棵树中最大的节点的度称为树的度


节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推


树的高度或深度:树中节点的最大层次


祖先:从根到该节点所经分支上的所有节点(根是所有节点的祖先)


森林:由m(m>0)棵互不相交的树的集合称为森林

2.二叉树:

节点的最多为二        

a.度为0的节点比度为二的节点多一个       

一个度为二的结点等价于一次合并

度为0的节点视为独立的集合,n个集合的合并需要n-1次操作        

故 n1=n2 - 1

任何其他树都可以转化为二叉树

b.左孩子右兄弟表示法

左边放子节点,右边放兄弟节点

2e34bb9e98a0140b2ec590933fca4656.gif

n叉树===二叉树(未确定性问题转化为确定性问题,无需管n)

c.遍历方式

前序遍历 :根->左->右

中序遍历 :左->根->右

后序遍历 :左->右->根 

d.完全二叉树(comple binary tree)

只有右节点的右节点的。。。是缺的

1.一层一层编号(左孩子为偶数 2*i ,右孩子为奇数 2*i+1 

2.连续编号===》可以用连续空间存储( 数 组 )

3.完全二叉树不是基于记录的(记录所有的数据)

           而是基于计算的(记住一个运算规则即可)

***算法/思维优化手段:记录方式转计算方式!!

e.满二叉树(full binary tree)

没有度为1的节点,要么就是度为0要么就是度为2的节点

f.完美二叉树(perfect binary tree)

Tips

二叉树的广义表:【“()”和递归以及树形结构的关系,真实包含关系

():空树

A/A(): A 

A(B,)/A(B):(逗号前左子树,逗号后右子树)

A(B,C):

A(B(,D),C(E))

g.排序二叉树

如果它的左子树不为空,那么左子树上所有节点的值均小于它的根节点的值

如果它的右子树不为空,那么右子树上所有节点的值均大于它的根节点的值

根节点的左子树和右子树均是二叉排序树

(可能退化为链表,所以有平衡二叉树的概念;二叉排序树的中序遍历是从小到大有序的)

二、结构操作:

1.创建新的树

2.创建新的节点

3.插入节点(按照二叉排序树)

4.清空节点

5.清空树

6.前序遍历

7.中序遍历

8.后序遍历

9.输出节点

10.输出树

11.寻找节点(按照二叉排序树)

  • 若等于根节点则成功返回
  • 如果小于根节点,则查找其左子树
  • 否则的话查找其右子树

12.删除节点

删除却可以分为三种不同的情况;
(1)删除的节点刚好是叶子结点(没有子结点)——直接删除

把删除节点置为NULL即可(删除节点的父节点指向NULL)

特例:如果删除节点是root节点,则root置为NULL即可

在这里插入图片描述  

(2)删除的节点只有左孩子或者只有右孩子,把删除节点的父节点指向删除节点的子结点即可

特例:如果删除节点是root节点,即可认为删除链表的头节点,把第二个节点当作表头即可

M6Ly9ibG9nLmNzZG4ubmV0L2k2MjIzNjcx,size_16,color_FFFFFF,t_70)

Tips:如果24只有右孩子:不用担心24的右孩子会不会比24的父母还大

因为如果24右孩子比24父母(45)还大,那么在建树的时候就会放到45的右孩子上

所以,根的左子树上的所有节点都要比它小

(3)删除的节点既有左孩子又有右孩子,两种删除方法

如果删除的节点有两个子结点,为保证二叉排序树的有序性

需要找到与删除节点键值最接近的两个节点

由排序二叉树的特性知,这两个节点位于删除节点左子树的最右节点,右子树的最左节点

然后将删除节点的父节点指向其中任意一个(例如左子树最右节点,简称替代节点)

让替代节点的右指针指向删除节点的右子树

当替代节点的父节点不是删除节点时,替代节点左指针指向删除节点左子树替代节点父节点指向替代节点的左子树(替代节点处于最右时没有左子树) 

特例1:删除的节点为root

特例2:替代节点的父节点是删除节点

①左子树“上位”,右子树合并到左子树,因为右子树上节点肯定都比左子树上的大,所以把右子树的根接到左子树的最右下角。

在这里插入图片描述

②左子树最右下角作为最接近被删节点的节点之一,可以直接替代子树的父母

在这里插入图片描述

以上的两种方法都可以作镜像变换,比如左子树最大对应右子树最小
 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


typedef struct Node
{
    int val;
    struct Node *lchild,*rchild;
} Node; //树的节点

typedef struct Tree
{
    int n;//节点个数
    Node * root;
} Tree;


Node *getNewNode(int val);
Tree *getNewTree(void);

void clearNode(Node *node);
void clearTree(Tree*tree);

void outputNode(Node *root);
void outputTree(Tree *tree);

Node *insertNode(Node *root,int val,int* ret);
int  insert(Tree *tree,int val);

void preorder(Tree *tree);
void preorderNode(Node *root);

void inorderNode(Node *root);
void inorder(Tree *tree);

void postorderNode(Node *root);
void postorder(Tree *tree);



Node *getNewNode(int val)
{
    Node *p=(Node*)malloc(sizeof(Node));
    p->val = val;
    p->lchild = p->rchild = NULL;
    return p;
}

Tree *getNewTree(void)
{
    Tree *tree = (Tree*)malloc(sizeof(Tree));
    tree->n = 0;
    tree->root = NULL;
    return tree;
}


void clearNode(Node *node)
{
    if(node == NULL) return ;
    clearNode(node->lchild);
    clearNode(node->rchild);
    free(node);
    return ;
}//用递归去遍历并清除树

void clearTree(Tree*tree)
{
    clearNode(tree->root);
    free(tree);
    return ;
}//


void outputNode(Node *root)
{
    if(root == NULL) return ;
    printf("%d",root->val);
    if(root->lchild == NULL && root->rchild == NULL) return ;
    printf("(");
    outputNode(root->lchild);
    printf(",");
    outputNode(root->rchild);
    printf(")");
    return ;
}

void outputTree(Tree *tree)
{
    printf("tree(%d)=",tree->n);
    outputNode(tree->root);
    return ;

}//转换为广义表


Node *insertNode(Node *root,int val,int* ret)
//二叉排序树,左子树小于根节点小于右节点,中序遍历!!!
{
    if(root == NULL)
    {
        *ret = 1;
        return getNewNode(val);//关键点!!!
    }
    if(root->val == val) return root;//什么都不干
    if(root->val > val) root->lchild = insertNode(root->lchild,val,ret);//比当前根节点小插入左侧
    else root->rchild = insertNode(root->rchild,val,ret);
    return root;
}//用递归方法插入

int insert(Tree *tree,int val)
{
    int flag = 0;
    tree->root = insertNode(tree->root,val,&flag);
    tree->n += flag;//flag为1插入成功,flag为0插入失败
    return 1;
}


void preorderNode(Node *root)
{
    if(root == NULL) return ;
    printf("%d->",root->val);
    preorderNode(root->lchild);
    preorderNode(root->rchild);
    return ;
}

void preorder(Tree *tree)
{
    printf("preorder:");
    preorderNode(tree->root);
    printf("NULL");
    printf("\n");
}


void inorderNode(Node *root)
{
    if(root==NULL) return ;
    inorderNode(root->lchild);
    printf("%d->",root->val);
    inorderNode(root->rchild);
}

void inorder(Tree *tree)
{
    printf("inorder:");
    inorderNode(tree->root);
    printf("NULL");
    printf("\n");
    return ;
}


void postorderNode(Node *root)
{
    if(root==NULL) return ;
    postorderNode(root->lchild);
    postorderNode(root->rchild);
    printf("%d->",root->val);
}

void postorder(Tree *tree)
{
    printf("postorder:");
    postorderNode(tree->root);
    printf("NULL");
    printf("\n");
    return ;
}



int main(void)
{
    srand(time(NULL));
    Tree* tree = getNewTree();
    for(int i=0; i<20; i++)
    {
        int val=rand()%100+1;
        insert(tree,val);
        outputTree(tree);
        printf("\n");
    }
    printf("\n");
    preorder(tree);
    inorder(tree);
    postorder(tree);
    return 0;
}

头晕版本:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


typedef struct Node
{
    int val;
    struct Node *lchild,*rchild;
} Node; //树的节点

typedef struct Tree
{
    int n;//节点个数
    Node * root;
} Tree;


Node *getNewNode(int val);
Tree *getNewTree(void);

void clearNode(Node *node);
void clearTree(Tree*tree);

void outputNode(Node *root);
void outputTree(Tree *tree);

Node *insertNode(Node *root,int val,int* ret);
int  insert(Tree *tree,int val);

void preorder(Tree *tree);
void preorderNode(Node *root);

void inorderNode(Node *root);
void inorder(Tree *tree);

void postorderNode(Node *root);
void postorder(Tree *tree);

Node *searchNode1(Tree* tree,int val);
Node *searchNode_Tree(Node* p,int val);
Node *searchTree(Tree* tree,int val);

Node *maxNode(Tree *tree);
Node *minNode(Tree *tree);

Node *parentNode(Node *Node, Tree *tree);





Node *getNewNode(int val)
{
    Node *p=(Node*)malloc(sizeof(Node));
    p->val = val;
    p->lchild = p->rchild = NULL;
    return p;
}

Tree *getNewTree(void)
{
    Tree *tree = (Tree*)malloc(sizeof(Tree));
    tree->n = 0;
    tree->root = NULL;
    return tree;
}


void clearNode(Node *node)
{
    if(node == NULL) return ;
    clearNode(node->lchild);
    clearNode(node->rchild);
    free(node);
    return ;
}//用递归去遍历并清除树

void clearTree(Tree*tree)
{
    clearNode(tree->root);
    free(tree);
    return ;
}//


void outputNode(Node *root)
{
    if(root == NULL) return ;
    printf("%d",root->val);
    if(root->lchild == NULL && root->rchild == NULL) return ;
    printf("(");
    outputNode(root->lchild);
    printf(",");
    outputNode(root->rchild);
    printf(")");
    return ;
}

void outputTree(Tree *tree)
{
    printf("tree(%d)=",tree->n);
    outputNode(tree->root);
    return ;

}//转换为广义表


Node *insertNode(Node *root,int val,int* ret)
//二叉排序树,左子树小于根节点小于右节点,中序遍历!!!
{
    if(root == NULL)
    {
        *ret = 1;
        return getNewNode(val);//关键点!!!
    }
    if(root->val == val) return root;//什么都不干
    if(root->val > val) root->lchild = insertNode(root->lchild,val,ret);//比当前根节点小插入左侧
    else root->rchild = insertNode(root->rchild,val,ret);
    return root;
}//用递归方法插入

int insert(Tree *tree,int val)
{
    int flag = 0;
    tree->root = insertNode(tree->root,val,&flag);
    tree->n += flag;//flag为1插入成功,flag为0插入失败
    return 1;
}


void preorderNode(Node *root)
{
    if(root == NULL) return ;
    printf("%d->",root->val);
    preorderNode(root->lchild);
    preorderNode(root->rchild);
    return ;
}

void preorder(Tree *tree)
{
    printf("preorder:");
    preorderNode(tree->root);
    printf("NULL");
    printf("\n");
}


void inorderNode(Node *root)
{
    if(root==NULL) return ;
    inorderNode(root->lchild);
    printf("%d->",root->val);
    inorderNode(root->rchild);
}

void inorder(Tree *tree)
{
    printf("inorder:");
    inorderNode(tree->root);
    printf("NULL");
    printf("\n");
    return ;
}


void postorderNode(Node *root)
{
    if(root==NULL) return ;
    postorderNode(root->lchild);
    postorderNode(root->rchild);
    printf("%d->",root->val);
}

void postorder(Tree *tree)
{
    printf("postorder:");
    postorderNode(tree->root);
    printf("NULL");
    printf("\n");
    return ;
}


Node *searchNode1(Tree* tree,int val)
{
    if(tree->root == NULL)
    {
        printf("The tree is empty!\n");
        return NULL;
    }
    Node* p = tree->root;
    while (p != NULL)
    {
        //找到了
        if(val == p->val)   return p;
        else if(val < p->val)   p = p->lchild;//在根的左子树
        else   p = p->rchild;   //在根的右子树
    }
    printf("Not Found!\n");
    return NULL;
}                           //  此处运用迭代进行遍历也可以用递归


Node *searchNode_Tree(Node* p,int val)
{
    if(p == NULL)           printf("Not Found!\n");
    else if(val < p->val)  return searchNode_Tree(p->lchild,val);   //在根的左子树
    else if(val > p->val)  return searchNode_Tree(p->rchild,val);   //在根的右子树
    else  return p;
    return NULL;
}

Node *searchTree(Tree* tree,int val)
{
    Node* p = tree->root;
    if(p == NULL)
    {
        printf("The tree is empty!\n");
        return NULL;
    }
    return searchNode_Tree(p,val);
}


Node *maxNode(Tree *tree)
{
    if(tree->root == NULL)  return NULL;
    Node *p = tree->root;
    while(p->rchild) p = p->rchild;  //跳出循环后,p指向最后一个右子节点
    return p;
}

Node *minNode(Tree *tree)
{
    if(tree->root == NULL)  return NULL;
    Node *p = tree->root;
    while(p->lchild) p = p->lchild;  //跳出循环后,p指向最后一个右子节点
    return p;
}


Node *parentNode(Node *Node, Tree *tree) //获取Node节点的父节点
{
    Node *p = tree->root;
    Node *parent = p;
    if (Node == NULL || tree->root == NULL || tree->root == Node) return NULL;

    while (p != NULL && p->val != Node->val)
    {
        parent = p;
        if (Node->val > p->val) p = p->rchild;   //每一次循环后parent总是p的父节点
        else   p = p->lchild;
    }
    if (p == NULL)
    {
        printf("节点Node不存在\n");
        return NULL;
    }
    return parent;
}


int main(void)
{
    srand(time(NULL));
    Tree* tree = getNewTree();
    for(int i=0; i<20; i++)
    {
        int val=rand()%100+1;
        insert(tree,val);
        outputTree(tree);
        printf("\n");
    }
    printf("\n");
    preorder(tree);
    inorder(tree);
    postorder(tree);
    int val;
    while(1)
    {
        scanf("%d",&val);
        printf("%p\n",searchNode1(tree,val));
        printf("%p\n",searchTree(tree,val));
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值