【数据结构】构造二叉树的三种方法
2016-05-22 15:22
316 查看
题目:
binary tree is a tree data structure in which each node has at most two children, which are referred to as the left child and the right child.1、Three Constructor:
creat a tree by copy.
creat a tree by a array.(using BFS)
creat a tree by preorder and inorder.
2、Methods:
clear: clear the tree.
copyTree: input old tree root and new tree root, copy it and get a new tree.
3、Static Methods:
three way to search tree.
Hint:
‘#’是表示该节点不存在,在下层判断的时候,可忽略该不存在的节点,主要在根据数组构造树中。如
1 2 3 # 4 5 6 7 # # 8
得到的是
1 / \ 2 3 \ / \ 4 5 6 / \ 7 8
即把二叉树作为一个方法封装起来。
附上头文件:
// // BinaryTree.hpp // C++ // // Created by my TA on 16/5/4. // Copyright © 2016年 lee. All rights reserved. // #ifndef BinaryTree_hpp #define BinaryTree_hpp #include <iostream> #include <vector> #include <queue> #include <stack> #define EMPTY_ELE '#' class BinaryTree { public: struct Node { char val; Node* left; Node* right; Node(char v, Node* l = NULL, Node* r = NULL): val(v), left(l), right(r) { } }; BinaryTree(const BinaryTree&); BinaryTree(std::vector<char>&); // created by preorder and inorder BinaryTree(const std::vector<char>& preOrder, const std::vector<char>& inOrder); ~BinaryTree(); Node* getRoot() const; void clear(); static void preOrder(void (*visite)(BinaryTree::Node*), Node*); static void inOrder(void (*visite)(BinaryTree::Node*), Node*); static void postOrder(void (*visite)(BinaryTree::Node*), Node*); private: Node * copyNode(Node * oldNode, Node * newNode); Node * root; }; #endif /* BinaryTree_hpp */
学到了不少东西。
先说说方法类的:
(一)、先序、中序、后序遍历二叉树,这是二叉树最基本的操作方法。
具体的实现方法是递归函数,通过visit的位置来控制先访问父节点,还是左子节点,还是右子节点。
具体实现代码如下:(其中visite的作用看具体的代码,这里只是一个抽象函数)
void preOrder(Node* _root) { if (_root) { visite(_root); preOrder(_root->left); preOrder(_root->right); } } void inOrder(Node* _root) { if (_root) { inOrder(_root->left); visite(_root); inOrder(_root->right); } } void postOrder(Node* _root) { if (_root) { postOrder(_root->left); postOrder(_root->right); visite(_root); } }
一个值得留心的点就是,搜索这个节点之前,要先判断它是否为空,可以用if(root)
(二)构造二叉树的三种方法
(1)、creat a tree by copy.
BinaryTree(const BinaryTree& other_root)
给你一棵树的根,让你跟着拷贝一棵树出来,我用的方法是递归,思路跟二叉树的先序遍历一样。(把visit换成new Node就行)。
PS.这里不能用中序、后序,因为你必须先有父节点才能访问它的子节点。所以父节点必须先被创造出来。
BinaryTree::BinaryTree(const BinaryTree& other_root) { if (other_root.root == NULL) {root = NULL; return;} root = copyNode(other_root.root, root); }
下面就是copy递归函数:
BinaryTree::Node* BinaryTree::copyNode(BinaryTree::Node * oldNode, BinaryTree::Node * newNode) { if (oldNode) { newNode = new Node(oldNode->val); newNode->left = copyNode(oldNode->left, newNode->left); newNode->right = copyNode(oldNode->right, newNode->right); return newNode; } else {return NULL;} }
【注意】对比一下两种情况:
newNode->left = copyNode(oldNode->left, newNode->left);
newNode->right = copyNode(oldNode->right, newNode->right);
和
copyNode(oldNode->left, newNode->left);
copyNode(oldNode->right, newNode->right);
即,要记得return,因为你传入进去的只是一个新建立的,作为传进去元素的一个副本,你在副本上做的操作,并不会影响原来的那个元素。
所以要记得把新建立的newNode return还给父节点的left和right。
(2)、creat a tree by a array.(using BFS)
即根据一个数组通过BFS的访问顺序来建立一棵二叉树。
所谓的BFS访问,即是一层一层访问下去。先访问level0、再访问level1、level2……访问对象可以是图、树等数据结构。
做BFS访问的主要工具是queue,通过push、front、pop的交替使用,来实现逐层访问。(深度搜索对应stack)
下面是代码实现:
BinaryTree::BinaryTree(vector<char> & array) { if (array.size() == 0) {root = NULL; return;} if (array[0] == '#') {root = NULL; return;} int i = 0; queue<BinaryTree::Node**> Q; BinaryTree::Node** temp; root = NULL; Q.push(&root); while (i != array.size() && !(Q.empty())) { temp = Q.front(), Q.pop(); if (array[i] == '#') { *temp = NULL; i++; } else { *temp = new Node(array[i++]); Q.push(&((*temp)->left)); Q.push(&((*temp)->right)); } } }
这里有一个要注意的问题,观察比较上面代码和下面代码:
BinaryTree::BinaryTree(vector<char> & array) { if (array.size() == 0) {root = NULL; return;} if (array[0] == '#') {root = NULL; return;} int i = 0; queue<BinaryTree::Node*> Q; BinaryTree::Node* temp; root = NULL; Q.push(root); while (i != array.size() && !(Q.empty())) { temp = Q.front(), Q.pop(); if (array[i] == '#') { temp = NULL; i++; } else { temp = new Node(array[i++]); Q.push(temp->left); Q.push(temp->right); } } }
一个是Node*类型的队列,一个是Node**型的队列。前者无法实现目的,后者可以。
为什么呢?
因为每次push进队列的是Node指针的一个一毛一样的副本,而不是Node指针它真身。所以你将那个副本front出来给temp,再在temp上面操作,是不会对真身产生任何影响的。
这里有两个可以解决的思路,一个是先赋值在push进去。
另一个是用指针的指针,即Node**,这样便可以直接访问Node指针,并且在Node指针上面做修改。(比如说改变它指向的元素的数值信息)。
(3)、creat a tree by preorder and inorder.用先序和中序建立二叉树。
一个先序的数列并不能唯一的确定一棵二叉树。
三种顺序访问二叉树而形成的数组顺序如下:
PreOrder(T) = T的根节点 + PreOrder(T的左子树) + PreOrder(T的右子树)
InOrder(T) = InOrder(T的左子树) + T的根节点 + InOrder(T的右子树)
PostOrder(T) = PostOrder(T的左子树) + PostOrder(T的右子树) + T的根节点
如果将他们都看成字符串或者字符,则“+”表示将字符串连接起来。
通过先序和中序建立二叉树的思路:
举例如先序遍历为DBACEGF,中序遍历为ABCDEFG。由先序的访问顺序,第一位必定是根节点。这里就是D,在看中序,中序的访问特点使得根节点D在中间,D左边的都是左子树,D右边的都是右子树。这样我们知道ABC为左子树,EFG为右子树。再继续用递归的思想,第二层的左边的先序遍历为BAC,中序遍历为ABC,按照刚刚的思路,B为父节点,B左边的A是左子树,C是右子树。在看看第二层的右边的先序遍历为EGF,中序遍历为EFG,则E为父节点,E的左边没有,则说明它的左子树不存在,FG都为右子树,继续下去:
先序GF,中序FG,则父节点为G,F为G的左子树。
这样子一棵二叉树便显然了。下面是核心代码:
BinaryTree::Node* buildTree(const char* pre, const char* in, int sum) { if (sum == 0) return NULL; char temp = pre[0]; //新地址的第一个元素 BinaryTree::Node* newNode = new BinaryTree::Node(temp); int i; for (i = 0; i < sum && in[i] != temp; ++i) {} int left_lenth = i; int right_lenth = sum - i - 1; if (left_lenth > 0) newNode->left = buildTree(&pre[1], &in[0], left_lenth); //注意传入的是地址,对于这个地址来说,pre[0]就是它的第一个元素 if (right_lenth > 0) newNode->right = buildTree(&pre[left_lenth + 1], &in[left_lenth + 1], right_lenth); return newNode; }
然后是语法上面的:
首先是在类里面的static函数,它在类里面,所以不管是不是static,定义的时候,都要加上类的作用域,但是不用再写static。
然后是
static void preOrder(void (*visite)(BinaryTree::Node*), Node*);的第一个参数,
void (*visite)(BinaryTree::Node*),这是一个函数指针类型,visite是函数的指针,它接受一个函数,这个函数的返回类型是void 形参是Node*类型。比如main函数里面的print函数,使用的时候,直接用visite(root)就好。其实就相当于形参和实参的关系。
相关文章推荐
- AVL树-自平衡二叉查找树(Java实现)
- 注册表的组织结构
- Ruby on Rails所构建的应用程序基本目录结构总结
- C#数据结构之顺序表(SeqList)实例详解
- Lua教程(七):数据结构详解
- SQLSERVER的非聚集索引结构深度理解
- 调整SQLServer2000运行中数据库结构
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#基础语法:结构和类区别详解
- 深入c# 类和结构的区别总结详解
- C#数据结构之队列(Quene)实例详解
- C#数据结构揭秘一
- c#结构和类的相关介绍
- C#数据结构之单链表(LinkList)实例详解
- C#中结构(struct)的部分初始化和完全初始化实例分析
- C#中类与结构的区别实例分析
- C#枚举类型与结构类型实例解析
- javascript实现表现、结构、行为分离的选项卡效果!
- 数据结构之Treap详解
- C语言二叉树的非递归遍历实例分析