二叉树操作复习

2017-08-29 11:46:37

writer:pprp

已经写了二叉树好几次了,但是还是有很多细节没有考虑完全

还有好多东西都没有考虑到,以后还是要写这个代码,把应该考虑的细节都考虑清楚

代码及讲解如下:(都测试过了,应该没问题,如果有问题请留言)

/*
@theme:树的建立和遍历
@writer:pprp
@start:10:00
@end:11:47
@declare:我建立的这个树好像跟教科书上的树方向反了一下,
但是不影响理解,教科书上的是大的在右边,小的在左边,我的恰好反了过来
@date:2017/8/28
*/

#include <bits/stdc++.h>

using namespace std;

struct tree
{
    int val;
    tree * l;
    tree * r;
};

//function 1 insert
//插入操作,比根节点大的要在左子树,比根节点小的要放在右子树
//test:ok
tree * Insert(tree *root, int val)
{
    tree * parent;
    tree * current;

    tree * newVal = new tree();

    newVal->val = val;
    newVal->r = NULL;
    newVal->l = NULL;

    if(root == NULL)
    {
        root = newVal;
    }
    else
    {
        current = root;
        while(current != NULL)
        {
            parent = current;
            if(current->val < val)//这里的符号要与下边的符号一致
            {
                current = current->l;
            }
            else
            {
                current = current->r;
            }
        }

        if(parent->val < val) //这里的符号要跟上边的符号一致
        {
            parent->l = newVal;
        }
        else
        {
            parent->r = newVal;
        }
    }
    return root;
}

//function 2: MakeEmpty
//test: ok
tree* MakeEmpty(tree * root)
{
    if(root != NULL)
    {
        MakeEmpty(root->r);
        MakeEmpty(root->l);
        delete root;
        root = NULL;
    }
    return NULL;
}

//function 3: Find value
//test:ok
//@param:返回一个指针,代表找到该节点的指针,否则返回NULL
tree* FindValue(tree * root,int val)
{
    if(root == NULL)
        return NULL;
    if(val < root->val)
        return FindValue(root->r,val);
    else if(val > root->val)
        return FindValue(root->l,val);
    else
        return root;
}

//function 4:Find Min
//由于树的构造是有大小之分的所以找小的直接向有子树找就好
//test:ok
tree* FindMin(tree * root)
{
    if(root == NULL)
        return NULL;
    else if(root->r == NULL)
        return root;
    else
        return FindMin(root->r);
}

//function 5: Find Max
//直接向右子树查找就好了
//test:ok
tree * FindMax(tree * root)
{
    if(root == NULL)
        return NULL;
    else if(root->l == NULL)
        return root;
    else
        return FindMax(root->l);
}

////function 6: delete
////test:error
////错误原因:思路不大对,如果只有一个子节点的情况,还需要判断这个本身是左边子节点还是右边子节点
//tree * Delete(tree * root, int val)
//{
//    tree * current = FindValue(root, val);
//    tree * tmp = NULL;
//    if(current->l == NULL && current->r == NULL)  //如果两个孩子都没有就可以直接删除掉
//    {
//        delete(current);
//    }
//    else if(current != NULL) //只有左孩子,将左孩子中最小的值变成原先节点
//    {
//        tmp = FindMin(current);
//        current->val = tmp->val;
//        delete(tmp);
//        tmp = NULL;
//    }
//    else if(current->r != NULL) //只有右孩子
//    {
//        tmp = FindMax(current);
//        current->val = tmp->val;
//        delete(tmp);
//        tmp = NULL;
//    }
//    else        //两个孩子都有
//    {
//        tmp = FindMin(current);
//        current->val = tmp->val;
//        delete(tmp);
//        tmp = NULL;
//    }
//}

//function 6: delete
//test:ok
//要删除的节点值为val,最后返回已经修改过的头结点
tree * Delete(tree * root, int val)
{
    tree * par;
    tree * kid;
    //第一部分找到该节点并找到该节点的父亲节点
    kid = root;
    while(kid != NULL)
    {

        if(kid->val > val)
        {
            par = kid;
            kid = kid->r;
        }
        else if(kid->val < val)
        {
            par = kid;
            kid = kid->l;
        }
        else if(kid->val == val)
        {
            break;  //这时候kid指向的是要找的节点 par记录的是要找的节点的父亲节点
        }
    }

    //没有找到的情况
    if(kid == NULL)
    {
        cout << "not find! " << endl;
        return NULL;
    }
    //现在开始判断是那种情况
    //1、如果是都是为空的情况
    if(kid->l == NULL && kid->r == NULL)
    {
        if(kid == root) //没有想到,如果是根节点,那么就直接赋值根节点为空
            root = NULL;
        if(par->l == kid)
            par->l = NULL;
        if(par->r == kid)
            par->r = NULL;
        delete(kid);
    }//2、只有一个节点的情况
    else if(kid->l == NULL || kid->r == NULL)
    {
        if(kid == root)
        {
            if(kid->r == NULL)
                root = kid->l;
            else
                root = kid->r;
            delete(root);
        }
        else  //分情况讨论
        {
              if(par->r == kid && kid->l)
              {
                    par->r = kid->l;
              }
              else if(par->r == kid && kid->r)
              {
                    par->r =  kid->r;
              }
              else if(par->l == kid && kid->l)
              {
                     par->l = kid->l;
              }
              else if(par->l == kid && kid->r)
              {
                     par->l = kid->r;
              }
              delete(kid);
        }
    } //3、有两个子节点的情况,这里采用将左边最小的替换找到节点的方案
    else
    {
           tree * tmp = FindMin(kid);
           kid->val = tmp->val;
           delete(tmp);
    }
    return root;
}

//前序遍历输出 -- ok
void preOut(tree * root)
{
    if(root != NULL)
    {
        cout << root->val <<" ";
        preOut(root->l);
        preOut(root->r);
    }
}

//中序遍历输出--ok
void midOut(tree * root)
{
    if(root != NULL)
    {
        midOut(root->l);
        cout << root->val << " ";
        midOut(root->r);
    }
}

//后序遍历输出--ok
void backOut(tree * root)
{
    if(root != NULL)
    {
        backOut(root->l);
        backOut(root->r);
        cout << root->val << " ";
    }
}

int main()
{
    int n;
    cin >> n;
    int a[100];

    tree * root = NULL;

    for(int i = 0 ; i < n ; i++)
    {
        srand((int)time(NULL)+i);
        a[i] = rand()%100;
    }

    for(int i = 0 ; i < n ; i++)
        cout << a[i] <<" ";
    cout << endl;

    //create a tree
    for(int i = 0 ; i < n ; i++)
    {
        root = Insert(root, a[i]);
    }

    cout << "preOut:" << endl;
    preOut(root);
    cout << endl;

//    root = MakeEmpty(root);
//    cout << "preOut:" << endl;
//    backOut(root);
//    cout << endl;

//    int val;
//    cin >> val;
//    tree * tmp = FindValue(root,val);
//    if(tmp != NULL)
//      cout << tmp->val << endl;

    tree * tmp = FindMax(root);
    if(tmp != NULL)
        cout << tmp->val << endl;

    tmp = FindMin(root);
    if(tmp != NULL)
        cout << tmp->val << endl;

    cout << "-----" << endl;

    int val;
    cin >> val;
    root = Delete(root,val);

    cout << "preOut:" << endl;
    preOut(root);
    cout << endl;

    return 0;
}
时间: 2024-10-26 19:26:27

二叉树操作复习的相关文章

iOS学习之iOS沙盒(sandbox)机制和文件操作复习

1.iOS沙盒机制 iOS应用程序只能在为该改程序创建的文件系统中读取文件,不可以去其它地方访问,此区域被成为沙盒,所以所有的非代码文件都要保存在此,例如图像,图标,声音,映像,属性列表,文本文件等. 1.1.每个应用程序都有自己的存储空间 1.2.应用程序不能翻过自己的围墙去访问别的存储空间的内容 1.3.应用程序请求的数据都要通过权限检测,假如不符合条件的话,不会被放行.     通过这张图只能从表层上理解sandbox是一种安全体系,应用程序的所有操作都要通过这个体系来执行,其中核心内容是

java泛型操作复习,以及讲解在android中使用的场景

android使用泛型的地方很多,比如集成自BaseAdapter实现封装的Adapter,对常用操作进行封装,但是需要对传进来的数据进行处理,此时就使用到泛型,示例如下: public abstract class EasyAdapter<T> extends BaseAdapter { private LayoutInflater inflater; private int layoutId; private List<T> mlist = new ArrayList<T

MySQL命令行操作复习

最近几天一直在做一个基于ThinkPHP的学生学籍管理系统的RBAC,用到Mysql固然不少,虽然现在Mysql的优秀的图形化软件已经不少了,可以显著地提高操作数据库的速度,自己最常用的两个是navicat跟Mysql-Front,其中最满意的是navicat,它不但界面简单,功能相对后者更完善一些,另外还支持mac ox系统,所以我多数还是用navicat.感觉有点扯远了,其实这篇文章我是想说的是,mysql图形软件固然提高了我们的效率,不过还是不能把操作MySQL的一些命令忘掉,毕竟不是每台

POJ 1577 Falling Leaves 二叉树操作

Description Figure 1 Figure 1 shows a graphical representation of a binary tree of letters. People familiar with binary trees can skip over the definitions of a binary tree of letters, leaves of a binary tree, and a binary search tree of letters, and

二叉树操作

问题0:      二叉树的非递归遍历方法 问题1: 判断一颗二叉树是否为二叉查找树. 问题2: 判断两个二叉树是否相同 问题3:      判断一棵树是否为平衡树 问题4:      寻找二叉树的最大和最短简单路径长度 问题5:      二叉树上简单路径的长度问题 解答0: [0.1]前序.使用栈,访问节点后先压入右儿子,再压入左儿子即可. 1 vector<int> preorderTraversal(TreeNode *root){ 2 stack<TreeNode*> s

python 文件操作复习一

复习文件操作 print "当前路径:" print os.getcwd() print "判断是否是一个文件:" print os.path.isfile(os.getcwd()) print "是否是一个目录:" print os.path.isdir(os.getcwd()) print os.system("ls") print "判断是否是绝对路径:" print os.path.isabs(&q

yum 操作复习

RPM与YUM是配合使用的. rpm负责从网站或指定的文件路径,获取到rpm软件包.也就是说你要安装什么服务或软件,就要先找到rpm包,下载下来.也就是通常说的配置yum源. 啥是yum源.你下载下的的rpm包就是咯. rpm 包 的包名一般有NAME  包是叫啥名字,一般与内容一致, VERSION 这个是版本号,通常理解就是升级到第几代了,RELEASE 这是软件包的升级基础,就是在此版本上做的更新.ARCH是编译这包,对CPU有啥要求,就是在什么框架下干活,NOARCH表示不限.想用啥用啥

文件操作复习

hello world 这次课程设计要求,对文件进行操作 总结一下以后好用 主要是对下列函数的理解 1 //fgetc(fp) 2 /*FILE *fp = NULL; 3 char ch; 4 char filename[MAX] = { 0 }; 5 printf("please input file name\n"); 6 scanf("%s", filename); 7 fp = fopen(filename, "r"); 8 if (f

二叉树操作总结

对于二叉树,有前序.中序.后序三种遍历方法,由于树的定义本身就是递归定义的,故采用递归方法实现三种遍历简洁易懂.若采用非递归访问,则需要使用栈来模拟递归的实现.三种遍历的非递归算法中,前序和后序较容易,而后序相对较难.   前序遍历 递归 非递归 树的遍历 中序遍历 递归 非递归 后序遍历 递归 非递归   层次遍历     计算树高        计算结点数       前序遍历[访问顺序:根结点-左孩子-右孩子] a> 前序遍历递归实现 1 void PreOrderRecursively(