二叉树及其扩展

本文探讨了二叉树的结构、遍历方式,包括前序、中序、后续和层序遍历。此外,介绍了搜索二叉树、平衡二叉树以及完全和满二叉树的概念。还讨论了在具有parent指针的二叉树中找到节点的后继节点的方法,并提出了折纸问题的解决方案,其与二叉树中序遍历的联系揭示了折痕方向的规律。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树的结构

class Node<V>{
    V value;
    Node left;
    Node right;
}

二叉树的遍历

分别是前序、中序、后续、层序遍历。

//递归实现的前序遍历
    static void preOrderRecur(Node* head){
        if(head == NULL)
            return;
        cout << head->data << " ";
        preOrderRecur(head->left);
        preOrderRecur(head->right);
    }
    //递归实现的中序遍历
    static void inOrderRecur(Node* head){
        if(head == NULL)
            return;
        inOrderRecur(head->left);
        cout << head->data << " ";
        inOrderRecur(head->right);
    }
    //递归实现的后序遍历
    static void posOrderRecur(Node*head){
        if(head == NULL)
            return;
        posOrderRecur(head->left);
        posOrderRecur(head->right);
        cout << head->data << " ";
    }
    //非递归实现的前序遍历
    static void preOrderUnRecur(Node* head){
        if(head == NULL)
            return;
        stack<Node*> s;
        s.push(head);
        while(!s.empty()){
            head = s.top();
            cout << head->data << " ";
            s.pop();
            if(head->right != NULL)
                s.push(head->right);
            if(head->left != NULL)
                s.push(head->left);
        }
    }
    //非递归实现的中序遍历
    static void inOrderUnRecur(Node* head){
        if(head == NULL)
            return;
        stack<Node*> s;
        while(!s.empty()|| head != NULL){
          if(head != NULL){
            s.push(head);
            head = head->left;
          }else{
            head = s.top();
            cout << head->data << " ";
            s.pop();
            head = head->right;
          }
        }
    }
    //非递归实现的后序遍历
    static void posOrderUnRecur_1(Node* head){
    if(head == NULL){
            return;
        }
        stack<Node*> s1;
        stack<Node*> s2;
        s1.push(head);
        while(!s1.empty()){
            head = s1.top();
            s1.pop();
            s2.push(head);
            if(head->left != NULL){
                s1.push(head->left);
            }
            if(head->right != NULL){
                s1.push(head->right);
            }
        }
        while(!s2.empty()){
            cout << s2.top()->data << " ";
            s2.pop();
        }
    }

 

//宽度优先遍历
    static void breadthFirstTravel(Node* head){
        if(head == NULL){
            return;
        }
        queue<Node*> q;
        q.push(head);
        while(!q.empty()){
            head = q.front();
            cout << head->data << " ";
            q.pop();
            if(head->left != NULL){
                q.push(head->left);
            }
            if(head->right != NULL){
                q.push(head->right);
            }
        }

    }

相关题目:求二叉树的宽度

 //求一颗二叉树的宽度
    static int treeMaxWidth(Node* head){
        if(head == NULL)
            return 0;
        queue<Node*> q;
        map<Node*,int> levelMap;
        q.push(head);
        levelMap[head] = 1;
        int maxWidth = 0;
        int curWidth = 0;
        int curLevel = 0;
        while(!q.empty()){
            head = q.front();
            q.pop();
            if(head->left != NULL){
                q.push(head->left);
                levelMap[head->left] = levelMap.find(head)->second + 1;
                //cout << levelMap.find(head)->second + 1 << " ";
            }
            if(head->right != NULL){
                q.push(head->right);
                levelMap[head->right] = levelMap.find(head)->second + 1;
            }
            if(levelMap.find(head)->second > curLevel){
                curWidth = 0;
                curLevel = levelMap.find(head)->second;
            }else{
                curWidth++;
            }
           // cout << curLevel << ": " << curWidth << endl;
            maxWidth = maxWidth >= curWidth ? maxWidth:curWidth;
        }
        return maxWidth + 1;
    }

二叉树的相关概念及其判断

搜索二叉树:每个节点的值一定大于左子树的最大值(或左子树为空),小于右子树的最小值(或右子树为空)。

class SearchBinaryReturnType{
public:
    bool isSearched;
    int smax;
    int smin;
    SearchBinaryReturnType(bool isSearched,int smax,int smin){
        this->isSearched = isSearched;
        this->smax = smax;
        this->smin = smin;
    }
};
static SearchBinaryReturnType sProcess(Node* head){
        if(head == NULL){
            SearchBinaryReturnType res(true,INT_MIN,INT_MAX);
            return res;
        }
        SearchBinaryReturnType leftData = sProcess(head->left);
        SearchBinaryReturnType rightData = sProcess(head->right);
        int smax = max(leftData.smax,head->data);
        smax = max(smax,rightData.smax);
        int smin = min(leftData.smin,head->data);
        smin = min(smin,rightData.smin);
        bool isSearched = leftData.smax < head->data && rightData.smin > head->data && leftData.isSearched && rightData.isSearched;
        //cout << head->data << " leftMax: " << leftData.smax << " rightmin:" << rightData.smin << " isSearched:" << isSearched << endl;
        SearchBinaryReturnType res(isSearched,smax,smin);
        return res;

    }
    static bool isSearchBinaryTree(Node* head){
        return sProcess(head).isSearched;
    }

平衡二叉树:每个节点左子树和右子树的高度相差不超过1.

class BalancedBinaryReturnType{
public:
    bool isBalanced;
    int height;
    BalancedBinaryReturnType(bool isBalanced,int height){
        this->isBalanced = isBalanced;
        this->height = height;
    }
};
 
static BalancedBinaryReturnType bProcess(Node* head){
        if( head == NULL){
            BalancedBinaryReturnType res(true,0);
            return res;
        }

        BalancedBinaryReturnType leftData = bProcess(head->left);
        BalancedBinaryReturnType rightData = bProcess(head->right);
        int height = leftData.height >= rightData.height ? (leftData.height + 1): (rightData.height + 1);
        bool isBalanced = leftData.isBalanced && rightData.isBalanced && abs(rightData.height - leftData.height)< 2;
        BalancedBinaryReturnType res(isBalanced,height);
        //cout << head->data << " height:" << height << " isBalanced:" << isBalanced << endl;
        return res;
    }

    static bool isBalancedBinaryTree(Node* head){
        return bProcess(head).isBalanced;
    }

完全二叉树与满二叉树:

//判断一颗二叉树是不是完全二叉树
    static bool isCompleteBinaryTree(Node* head){
        if(head == NULL)
            return true;
        bool leaf = false;
        queue<Node*> q;
        q.push(head);
        while(!q.empty()){
            head = q.front();
            q.pop();
            if(
               (head->left == NULL && head->right != NULL)
               ||
               (leaf && (head->left != NULL || head->right) != NULL)
               )
                return false;
            if(head->left != NULL){
                q.push(head->left);
            }
            if(head->right != NULL){
                q.push(head->right);
            }
            else{
                leaf = true;
            }
        }
        return true;
    }

    //判断一棵树是不是满二叉树

class FullBinaryReturnType{
public:
    int height;
    int nodes;
    FullBinaryReturnType(int height,int nodes){
        this->height = height;
        this->nodes = nodes;
       // cout << "init: height(" << this->height << ")  nodes(" << this->nodes << ")" << endl;
    }
};

    static FullBinaryReturnType fProcess(Node* head){
        if(head == NULL){
            FullBinaryReturnType res(0,0);
            return res;
        }
        FullBinaryReturnType leftData = fProcess(head->left);
        FullBinaryReturnType rightData = fProcess(head->right);
       // cout << "LH: " << leftData.height << " RH:" << rightData.height << " LN: " << leftData.nodes << " RN: " << rightData.nodes << endl;
        int height = max(leftData.height,rightData.height) + 1;
        int nodes = leftData.nodes + rightData.nodes + 1;
        //cout << head->data << " height:" << height << " nodes:"<< nodes << endl;
        FullBinaryReturnType res(height,nodes);
        return res;
    }

    static bool isFullBinaryTree(Node* head){
        FullBinaryReturnType res = fProcess(head);
        return ((1 << res.height) - 1 == res.nodes);
    }

扩展题目:

1. 给定两个节点,找到它们的最低公共祖先节

 static Node* findLowestCommonAncester(Node* head,Node* n1,Node* n2){
        if(head == NULL || head == n1 || head == n2)
            return head;
        Node* l = findLowestCommonAncester(head->left,n1,n2);
        Node* r = findLowestCommonAncester(head->right,n1,n2);
        if(l != NULL && right != NULL){
            return head;
        }
        return l != NULL ? l : r;
    }

2. 在二叉树中找到一个节点的后继节点。

【题目】 现在有一种新的二叉树节点类型如下:

public class Node {

public int value;

public Node left;

public Node right;

public Node parent;

public Node(int val) { value = val; }

}

该结构比普通二叉树节点结构多了一个指向父节点的parent指针。 假设有一棵Node类型的节点组成的二叉树,树中每个节点的parent指针都正确地指向自己的父节点,头节 点的parent指向null。 只给一个在二叉树中的某个节点node,请实现返回node的后继节点的函数。 在二叉树的中序遍历的序列中, node的下一个节点叫作node的后继节点。

class Node_3{
public:
    int data;
    Node_3* l;
    Node_3* r;
    Node_3* parent;
    Node_3(int data,Node_3*p){
        this->data = data;
        this->parent = p;
        this->l = NULL;
        this->r = NULL;
    }
};

static Node_3* findSuccessorNode(Node_3* node){
        if( node == NULL){
            return NULL;
        }
        if(node->r != NULL){
            node = node->r;
            while(node != NULL && node->l != NULL){
                node = node->l;
            }
            return node;
        }
        if( node == node->parent->l){
            return node->parent;
        }else{
           // Node* p = node->parent;
            while(node->parent != NULL &&node != node->parent->l)
                node = node->parent;
            return node->parent;
        }
    }

寻找一个节点的前驱节点

//在二叉树中找到一个节点的前驱节点
    static Node_3* findPreNode(Node_3* node){
        if(node == NULL)
            return NULL;
       // cout << node->data << endl;
        if(node->l != NULL){
            node = node->l;
            while(node->r != NULL && node != NULL)
                node = node->r;
            if(node->l != NULL)
                node = node->l;
            return node;
        }
        else{
            //cout << node->data << endl;
            while(node->parent != NULL && node->parent->r != node){
                node = node->parent;
                //cout << node->data << endl;
            }

            return node->parent;
        }

    }

 

二叉树的序列化和反序列化

序列化:内存里的一棵树如何转化成字符串形式。

反序列化:从字符串形式变成内存里的树。

 static string serializePreTree(Node* root){
        if(root == NULL)
            return "# ";
        stringstream ss;
        ss << root->data;
        string str = ss.str() + " ";
        str += serializePreTree(root->left);
        str += serializePreTree(root->right);
        return str;
    }

    static Node* recnPreOrder(queue<string>& nodeStr){
        string str = nodeStr.front();
        nodeStr.pop();
        if(str == "#"){
            return NULL;
        }
        int data;
        sscanf(str.data(),"%d",&data);
        Node* root = new Node(data);
        root->left = recnPreOrder(nodeStr);
        root->right = recnPreOrder(nodeStr);
        return root;

    }

    static void split(const std::string& s, std::queue<std::string>& v, const std::string& c)
    {
      std::string::size_type pos1, pos2;
      pos2 = s.find(c);
      pos1 = 0;
      while(std::string::npos != pos2)
      {
        v.push(s.substr(pos1, pos2-pos1));

        pos1 = pos2 + c.size();
        pos2 = s.find(c, pos1);
      }
      if(pos1 != s.length())
        v.push(s.substr(pos1));
    }

    static Node* recnByPreString(string str){
        queue<string> q;
        string c = " ";
        split(str,q,c);
        return recnPreOrder(q);
    }

这里使用前序遍历的顺序进行序列化。

扩展:折纸问题

请把一段纸条竖着放在桌子上,然后从纸条的下边向上方对折1次,压出折痕后 展开。 此时折痕是凹下去的,即折痕突起的方向指向纸条的背面。 如果从纸条的下边向上方连续对折2次,压出折痕后展开,此时有三条折痕,从 上到下依次是下折痕、下折痕和上折痕。 给定一个输入参数N,代表纸条都从下边向上方连续对折N次。 请从上到下打印所有折痕的方向。 例如:N=1时,打印: down N=2时,打印: down down up

分析:可以通过实际折纸来寻找规律

当 N = 1:                          down

当 N = 2:           down      down            up

当 N = 3: down down up down  down  up  up

。。。

可以看出折痕的方向具有一定规律,并且该规律与二叉树十分相似,每一个节点的左子树为 down,右子树为 up。打印结果就是二叉树的中序遍历。

 static void paperFolding (int i,int N,bool down){
        if(i > N){
            return;
        }
        paperFolding(i + 1,N,true);
        cout << (down ? "down " : "up ");
        paperFolding(i + 1,N,false);
    }

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值