二叉树的基本操作
实现了一颗简单的二叉树的建立和访问
用递归和迭代实现BFS、DFS
最简单的构造、遍历一个二叉树
递归是容易写出来和理解的方式;
为了让树长得更均衡一点,一个?代表一个空节点;
这颗树的节点是一个character;
#include<iostream>
using namespace std;
//树的一个节点
struct TreeNode {
char data;
TreeNode* leftNode;
TreeNode* rightNode;
TreeNode(char c) : data(c), leftNode(NULL), rightNode(NULL) {}
};
用递归的方式先序遍历这棵树;
void preOrder(TreeNode* root) {
if (root == NULL) {
// cout << 66 << endl;
return;
}
cout << root->data << endl;
preOrder(root->leftNode);
preOrder(root->rightNode);
return;
}
建造一颗二叉树;如果一直用先序的方法建造,最后这棵树会变成只有左子树;
所以读入一个?表示这是一个空节点,就会转而建造右子树;
TreeNode* build(int& posi, string s, int& n) {
if (posi > n)return NULL;
char c = s[posi++];
if (c=='?')return NULL;
TreeNode* t = new TreeNode(c);
t->leftNode = build(posi, s, n);
t->rightNode = build(posi, s, n);
return t;
}
先读取一个字符串,然后用这个字符串建造一个二叉树;
建造完成后用先序遍历的方式打印他;
因为建造和打印的方式都是先序,所以输入和输出的顺序应该是一样的;
但是问号除外,因为把有问号的地方建造成了一个空节点。
int main() {
int position = 0;
string str;
cin >> str;
int n = str.size() - 1;
TreeNode* t1 = build(position, str, n);
preOrder(t1);
return 0;
}
二叉排序树
构造一个二叉排序树。也使用递归的方法;
构造的同时把爸爸节点打印出来。
#include<iostream>
using namespace std;
//树的一个节点
#define MAX 6
struct TreeNode {
int data;
TreeNode* leftNode;
TreeNode* rightNode;
TreeNode(int c) : data(c), leftNode(NULL), rightNode(NULL) {}
};
树的节点结构和刚才类似,除了数据类型变成了integer;
先序遍历的方法也没有变,除了格式做了一些调整;
void preOrder(TreeNode* root) {
if (root == NULL) {
// cout << 66 << endl;
return;
}
cout << root->data << ',';
preOrder(root->leftNode);
preOrder(root->rightNode);
return;
}
中序遍历,这样打印的二叉树才是由小到大的顺序;
void midOrder(TreeNode* root) {
if (root == NULL) {
// cout << 66 << endl;
return;
}
midOrder(root->leftNode);
cout << root->data <<' ';
midOrder(root->rightNode);
return;
}
建造一颗有顺序的二叉树,并且建造的时候打印出来建造的节点和他的爸爸节点。
当然啦是没必要打印的,只是为了能看到这棵树的结构是怎样的;
TreeNode* build(TreeNode* root, int x, int father) {
if (root == NULL) {
root = new TreeNode(x);
cout << "in: "<< x<<endl;
cout <<" father:"<< father << endl;
}
else if (x < root->data) root->leftNode = build(root->leftNode, x, root->data);
else root->rightNode = build(root->rightNode, x, root->data);
return root;
}
在main函数里建造一颗二叉排序树,并且用中序遍历和先序遍历的方法把他打印出来;
输入完数字后CTRL+Z表示输入完成;
int main() {
int x = 0;
TreeNode* t1 = NULL;
while(cin>>x)t1=build(t1, x, -1);
midOrder(t1);
cout << endl;
preOrder(t1);
return 0;
}
最后的运行结果:
如果把这棵树画出来:
树的遍历方法——BFS DFS
树的遍历方法可以用深度和宽度两种方法。
(1)dfs
用递归的方法可以以前序、中序、后序三种方式搜索一颗树,上面用到的就是递归的方法。
非递归的方法可以用栈来实现,前序的非递归方法有两个编码思路:
访问栈顶,然后把他的左右节点入栈;
根节点入栈以后,进入循环。依次把栈里的内容弹出,然后把弹出的节点右节点和左节点入栈(如果不为空);
void preOrder(TreeNode* root) {
if (!root) {
cout << "empty tree";
return;
}
stack<TreeNode*> s;
s.push(root);
while (!s.empty())
{
TreeNode* t = s.top();
s.pop();
cout << t->data;
if (t->rightNode!=NULL)s.push(t->rightNode);
if (t->leftNode!=NULL)s.push(t->leftNode);
}
}
另一种思路是顺着左边的分支访问、入栈,直到遇到了空节点,就访问栈顶的右子树;
在循环里这个右子树也顺着左边的分支。
void preOrder(TreeNode* root) {
stack<TreeNode*> s;
TreeNode* p = root;
while (p != NULL || s.empty() != NULL)
{
if (p != NULL) {
cout << p->data;
s.push(p);
p = p->leftNode;
}
else {
p = s.top();
s.pop();
p = p->rightNode;
}
}
}
(2)bfs
可以用队列实现。访问队头的结点,把他的左右子树加到队尾,这样就是一层一层的遍历了;
> void bfs(TreeNode* root) {
> if (root == NULL)return;
> queue<TreeNode*> q;
> q.push(root);
> while (!q.empty()) {
> TreeNode* t;
> t = q.front();
> q.pop();
> cout << t->data;
> if (t->leftNode != NULL)q.push(t->leftNode);
> if (t->rightNode != NULL)q.push(t->rightNode);
> } }