zoukankan      html  css  js  c++  java
  • 数据结构 (二叉树)1

    二叉树:每个节点最多有两棵字数,左子树和右子树

    完全二叉树:叶节点只能出现在最下层和次下层,而且最下面一层的结点都集中在该层最左边的若干位置的二叉树。每层节点都完全填满,在最后一层上如果不是满的,则只缺少右边的若干节点。

    满二叉树:要么叶子节点,要么节点同时具有左右子树

    存储方式:

    1)顺序存储: 遍历速度上有优势,但占空间大,是非主流二叉树。二叉树通常以链式存储

        typedef char datatype;

        typedef struct node{

             datatype data;

             int lchild, rchild;

            int parent;

       } Node;

    Node tree[Length];

    2)链式存储: 

        typedef char datatype;

        typedef struct node{

       datatype data;

      struct node *lchild;

          struct node *rchild;

       }node;

    node *tree;

    二叉树的遍历

    前序遍历:根节点->左子树->右子树

    中序遍历:左子树->根节点->右子树

    后序遍历:左子树->右子树->根节点

    实现:

    问题:

    取地址符&

      int a=0;

      int *p=&a;

      int *M=& 0X01000; wrong, 对于一个数值常量,没有地址。 变量有地址要有一个存储单元对变量进行标识

    引用&

      int a=0;

      int &r=a;

    new delete 和malloc free: new 是operator, malloc是函数

    创建:

    void creatBinTree(node * t)
    {
    char c;
    cin>>c;
    if(c=='#')
    t=NULL;
    else
    {
    // t=(node *) malloc(sizeof(node *));
    t=new node;
    t->data=c;
    creatBinTree(t->lchild);
    creatBinTree(t->rchild);
    }
    
    }
    
    
    
    int main()
    {
    
    node * tree1;
    creatBinTree(tree1);
    
    visit(tree1);
    return 0;
    }

    错误,tree没有创建成功,因为没有改变tree;

    将函数改为:

    void creatBinTree(node * &t)

    成功

    分析:

    C++中的值传递,指针传递,引用传递

    1)值传递:

      形参是实参的拷贝,改变形参的值不会影响外部实参的值(如果函数内部需要修改参数,并且不希望这个改变影响其他调用,采用值传递)

    2)指针传递:

         形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行操作。

    3)引用传递

        形参相当于实参的“别名”, 对形参的操作,就是对实参的操作。在引用传递过程中,被调函数的形式参数虽然作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。

    void change1(int n)
    {
    
        cout<<"值传递--函数操作地址"<<&n<<endl;
        n++;
        }
    void change2(int &n)
    {
        cout<<"引用传递--函数操作地址"<<&n<<endl;
        n++;
    }
    
    void change3(int *n)
    {
        cout<<"指针传递--函数操作地址"<<n<<endl;
        *n=*n+1;
    }
    int main()
    {
        int n=10;
        cout<<"实参的地址"<<&n<<endl;
        change1(n);
        cout<<n<<endl;
        change2(n);
        cout<<n<<endl;
        change3(&n);
        cout<<n<<endl;
        return 0;
    }

    引用于指针传递的区别:

    1)引用被创建的同时必须被初始化(指针可在任何时候初始化)

    2)不能有NULL引用,必须有合法的存储单元关联

    3)引用一旦初始化,就不能改变引用的关系(指针可以随时改变所指的对象)

    指针传递的本质是值传递,传递一个地址值。

    1)递归方式访问二叉树:

    void visit(node * root)
    {
        if(root)
        {
            cout<<root->data<<endl;
            if(root->lchild)
            {
                visit(root->lchild);
            }
    
            if(root->rchild)
            {
                visit(root->rchild);
            }
        }
    }

    2)非递归的访问二叉树:

    (递归操作遍历过的根节点还要回来,所以需要存起来)-->栈存储  

      对于前序遍历,优先访问根节点,然后在分别访问左孩子和右孩子。

      对于任一节点P:

      1)访问节点P,并将节点P入栈;

      2)判断节点P的左孩子是否为空,若为空,则取栈顶节点并出栈,将栈顶节点的右孩子置为当前的节点P,看其是否为空,若不为空,则循环1), 如为空,则继续出栈。

        若左子树不为空,将P的左孩子置为当前的节点P,重复1)

      3)直到P为NUL并且栈为空

    存在栈中是为了倒叙访问右节点

    ABD入先后入栈,并在入栈时输出,

    D的左孩子为空,将D出栈,但不输出,将其有孩子作为当前节点,为空,将B出栈,并将右节点E作为当前节点,入栈,输出E。

    E和D情况相同,类推。。。

    void preOrder2(node *root)
    {
        stack <node*>s;
        node * p=root;
        while(p!=NULL||!s.empty())
        {
            while(p!=NULL)
            {
                s.push(p);
                cout<<p->data<<endl;
                p=p->lchild;
            }
            if(!s.empty())
            {
                p=s.top();
                s.pop();
                p=p->rchild;
            }
        }
    
    }

    中序遍历为出栈的时候再输出

    后序遍历稍稍复杂

  • 相关阅读:
    C# 控制台应用程序输出颜色字体[更正版]
    ORM for Net主流框架汇总与效率测试
    php 去掉字符串的最后一个字符
    bzoj1185 [HNOI2007]最小矩形覆盖 旋转卡壳求凸包
    bzoj [Noi2008] 1061 志愿者招募 单纯形
    bzoj1009 [HNOI2008] GT考试 矩阵乘法+dp+kmp
    扩展欧几里得(ex_gcd),中国剩余定理(CRT)讲解 有代码
    BZOJ 2103/3302/2447 消防站 树的重心【DFS】【TreeDP】
    hihocoder 1449 后缀自动机三·重复旋律6
    hihocoder 后缀自动机二·重复旋律5
  • 原文地址:https://www.cnblogs.com/fanhaha/p/7051958.html
Copyright © 2011-2022 走看看