算法05
创建一颗二叉树使用递归版实现前中后序遍历这颗二叉树和使用队列实现层序遍历
#include<iostream> #include<queue> #include<cstdio> using namespace std; struct TreeNode { char data; TreeNode *lchild, *rchild; }; class Tree { private: TreeNode *head; queue<TreeNode *> q; public: Tree() { head = NULL; } public: void create_tree() { cout << "请按照前序遍历的方式建造一棵树,#代表空节点!\n"; _cree_tree(head); } protected: void _cree_tree(TreeNode * &t) { char ch; cin >> ch; if ('#' == ch) { t = NULL; return; } t = new TreeNode; t->data = ch; _cree_tree(t->lchild); _cree_tree(t->rchild); } public: void prelook() { if (NULL == head) { cout << "这是一颗空树\n"; return; } cout << "前序遍历:"; _prelook(head); cout << endl; } protected: void _prelook(TreeNode * &t) { if (NULL == t) { return; } cout << t->data << " "; _prelook(t->lchild); _prelook(t->rchild); } public: void inlook() { if (NULL == head) { cout << "这是一颗空树\n"; return; } cout << "中序遍历:"; _inlook(head); cout << endl; } protected: void _inlook(TreeNode * &t) { if (NULL == t) { return; } _inlook(t->lchild); cout << t->data << " "; _inlook(t->rchild); } public: void endlook() { if (NULL == head) { cout << "这是一颗空树\n"; return; } cout << "后序遍历:"; _endlook(head); cout << endl; } protected: void _endlook(TreeNode * &t) { if (NULL == t) { return; } _endlook(t->lchild); _endlook(t->rchild); cout << t->data << " "; } public: void levellook() { if (NULL == head) { cout << "这是一颗空树!\n"; return; } cout << "层序遍历:"; _begin(head); _next(); cout << endl; } protected: void _begin(TreeNode* & t) { q.push(t); } void _next() { while (!q.empty()) { TreeNode * item = q.front(); q.pop(); cout << item->data << " "; if (NULL != item->lchild) { q.push(item->lchild); } if (NULL != item->rchild) { q.push(item->rchild); } } } public: ~Tree() { _delete(head); } protected: void _delete(TreeNode * & t) { if (NULL == t) { return; } _delete(t->lchild); _delete(t->rchild); delete t; } }; int main() { while (true) { Tree tree; char ch; cout << "如果要创建一颗树请输入1,否则输入2:"; cin >> ch; int flag = 1; switch (ch) { case '1': tree.create_tree(); break; case '2': break; default: cout << "你的输入有问题,请重新输入\n"; flag = 0; break; } if (0 == flag) { continue; } if ('2' == ch) { break; } while (true) { cout << "请选择你要进行的操作! 1.前序遍历 2.中序遍历 3.后续遍历 4.层序遍历 其他输入退出操作\n"; char order; cin >> order; switch (order) { case '1': tree.prelook(); break; case '2': tree.inlook(); break; case '3': tree.endlook(); break; case '4': tree.levellook(); break; default: order = '#'; break; } getchar(); if ('#' == order) { break; } } } return 0; }
二叉树非递归版本的前序遍历
#include<iostream> #include<stack> //使用系统栈 #include<cstdio> using namespace std; struct TreeNode { char data; TreeNode *lchild, *rchild; }; void createTree(TreeNode * &t) { char ch; cin >> ch; if ('#' == ch) { t = NULL; return; } t = new TreeNode; t->data = ch; createTree(t->lchild); createTree(t->rchild); } void preLook(TreeNode *t) //非递归版本的前序遍历二叉树 { stack<TreeNode *> st; st.push(t); while (!st.empty()) { TreeNode *item = st.top(); cout << item->data << " "; st.pop(); if (NULL != item->rchild) st.push(item->rchild); if (NULL != item->lchild) st.push(item->lchild); } cout << endl; } int main() { TreeNode *tr; cout << "请使用前序遍历创建一颗二叉树\n"; createTree(tr); cout << endl; preLook(tr); return 0; }
二叉树非递归的中序遍历
#include<iostream> #include<stack> //使用系统栈 #include<cstdio> using namespace std; struct TreeNode { char data; TreeNode *lchild, *rchild; }; void createTree(TreeNode * &t) { char ch; cin >> ch; if ('#' == ch) { t = NULL; return; } t = new TreeNode; t->data = ch; createTree(t->lchild); createTree(t->rchild); } void inLook(TreeNode *t) //非递归版本的前序遍历二叉树 { stack<TreeNode *> st; while (!st.empty() || NULL != t) { if (NULL != t) { st.push(t); t = t->lchild; } else { TreeNode *item = st.top(); st.pop(); cout << item->data << " "; t = item->rchild; } } cout << endl; } int main() { TreeNode *tr; cout << "请使用前序遍历创建一颗二叉树\n"; createTree(tr); cout << endl; inLook(tr); return 0; }
二叉树非递归的后续遍历
#include<iostream> #include<stack> //使用系统栈 #include<cstdio> using namespace std; struct TreeNode { char data; TreeNode *lchild, *rchild; }; void createTree(TreeNode * &t) { char ch; cin >> ch; if ('#' == ch) { t = NULL; return; } t = new TreeNode; t->data = ch; createTree(t->lchild); createTree(t->rchild); } //后续遍历我们仿照前序遍历的思想,现将数据按照 中 右 左 压入一个栈,然后将原本前序遍历的应该打印的语句替换为压入另一个栈就变成了 左 右 中 的顺序 //最后一次性打印另一个栈 void endLook(TreeNode *t) //非递归版本的前序遍历二叉树 { if (NULL != t) { stack<TreeNode *> st,st1; st.push(t); while (!st.empty()) { t = st.top(); st.pop(); st1.push(t); if (NULL != t->lchild) { st.push(t->lchild); } if (NULL != t->rchild) { st.push(t->rchild); } } while (!st1.empty()) { cout << st1.top()->data << " "; st1.pop(); } cout << endl; } } int main() { TreeNode *tr; cout << "请使用前序遍历创建一颗二叉树\n"; createTree(tr); cout << endl; endLook(tr); return 0; }
一段Java代码直观的打印整颗二叉树
package class_04; public class Code_02_PrintBinaryTree { public static class Node { public int value; public Node left; public Node right; public Node(int data) { this.value = data; } } public static void printTree(Node head) { System.out.println("Binary Tree:"); printInOrder(head, 0, "H", 17); System.out.println(); } public static void printInOrder(Node head, int height, String to, int len) { if (head == null) { return; } printInOrder(head.right, height + 1, "v", len); String val = to + head.value + to; int lenM = val.length(); int lenL = (len - lenM) / 2; int lenR = len - lenM - lenL; val = getSpace(lenL) + val + getSpace(lenR); System.out.println(getSpace(height * len) + val); printInOrder(head.left, height + 1, "^", len); } public static String getSpace(int num) { String space = " "; StringBuffer buf = new StringBuffer(""); for (int i = 0; i < num; i++) { buf.append(space); } return buf.toString(); } public static void main(String[] args) { Node head = new Node(1); head.left = new Node(-222222222); head.right = new Node(3); head.left.left = new Node(Integer.MIN_VALUE); head.right.left = new Node(55555555); head.right.right = new Node(66); head.left.left.right = new Node(777); printTree(head); head = new Node(1); head.left = new Node(2); head.right = new Node(3); head.left.left = new Node(4); head.right.left = new Node(5); head.right.right = new Node(6); head.left.left.right = new Node(7); printTree(head); head = new Node(1); head.left = new Node(1); head.right = new Node(1); head.left.left = new Node(1); head.right.left = new Node(1); head.right.right = new Node(1); head.left.left.right = new Node(1); printTree(head); } }
题目:在二叉树中找到一个节点的后继节点
该结构比普通二叉树节点结构多了一个指向父节点的parent指针。假 设有一 棵Node类型的节点组成的二叉树,树中每个节点的parent指针 都正确地指向 自己的父节点,头节点的parent指向null。只给一个在 二叉树中的某个节点 node,请实现返回node的后继节点的函数。在二 叉树的中序遍历的序列中, node的下一个节点叫作node的后继节点
常规思路:给定一个结点,如果要得到他的后继结点,我们只需要中序遍历这颗二叉树,然后得到答案
更优的思路:给定一个结点,有两种情况,第一种,这个结点有右子树,找到右子树最左的结点就是他的后继结点。第二种,这个结点没有后继结点,就通过parent指针,判断当前节点是否是父节点的左孩子,不是的话接着往上找,知道找到当前节点是父节点的左孩子,如果找到最后当前节点的父节点是NULL那么给出的这个结点是中序遍历中的最后一个结点,这种思路给出java代码
package class_04; public class Code_03_SuccessorNode { public static class Node { public int value; public Node left; public Node right; public Node parent; public Node(int data) { this.value = data; } } public static Node getSuccessorNode(Node node) { if (node == null) { return node; } if (node.right != null) { return getLeftMost(node.right); } else { Node parent = node.parent; while (parent != null && parent.left != node) { node = parent; parent = node.parent; } return parent; } } public static Node getLeftMost(Node node) { if (node == null) { return node; } while (node.left != null) { node = node.left; } return node; } public static void main(String[] args) { Node head = new Node(6); head.parent = null; head.left = new Node(3); head.left.parent = head; head.left.left = new Node(1); head.left.left.parent = head.left; head.left.left.right = new Node(2); head.left.left.right.parent = head.left.left; head.left.right = new Node(4); head.left.right.parent = head.left; head.left.right.right = new Node(5); head.left.right.right.parent = head.left.right; head.right = new Node(9); head.right.parent = head; head.right.left = new Node(8); head.right.left.parent = head.right; head.right.left.left = new Node(7); head.right.left.left.parent = head.right.left; head.right.right = new Node(10); head.right.right.parent = head.right; Node test = head.left.left; System.out.println(test.value + " next: " + getSuccessorNode(test).value); test = head.left.left.right; System.out.println(test.value + " next: " + getSuccessorNode(test).value); test = head.left; System.out.println(test.value + " next: " + getSuccessorNode(test).value); test = head.left.right; System.out.println(test.value + " next: " + getSuccessorNode(test).value); test = head.left.right.right; System.out.println(test.value + " next: " + getSuccessorNode(test).value); test = head; System.out.println(test.value + " next: " + getSuccessorNode(test).value); test = head.right.left.left; System.out.println(test.value + " next: " + getSuccessorNode(test).value); test = head.right.left; System.out.println(test.value + " next: " + getSuccessorNode(test).value); test = head.right; System.out.println(test.value + " next: " + getSuccessorNode(test).value); test = head.right.right; // 10's next is null System.out.println(test.value + " next: " + getSuccessorNode(test)); } }
二叉树的前序遍历序列化和反序列化
#include<iostream> #include<string> #include<queue> using namespace std; queue<char> qu; struct TreeNode { char data; TreeNode *lchild, *rchild; }; void createTree(TreeNode * &t) { char ch; cin >> ch; if ('#' == ch) { t = NULL; return; } t = new TreeNode; t->data = ch; createTree(t->lchild); createTree(t->rchild); } string serByPre(TreeNode *&t) //先序遍历的序列化 !为分隔符 #为空节点 { if (NULL == t) { return (string)"#!"; } string res; res += t->data; res += '!'; res += serByPre(t->lchild); res += serByPre(t->rchild); return res; } void reconPreOrder(TreeNode *&t) { char ch = qu.front(); qu.pop(); if ('#' == ch) { t = NULL; return; } t = new TreeNode; t->data = ch; reconPreOrder(t->lchild); reconPreOrder(t->rchild); } void preOrder(TreeNode *t) //递归前序遍历用于检验反序列化是否成功 { if (NULL == t) { return; } cout << t->data << " "; preOrder(t->lchild); preOrder(t->rchild); } int main() { TreeNode *tr; cout << "请使用前序遍历创建一颗二叉树\n"; createTree(tr); //使用前序遍历创建一颗二叉树 cout << endl; string s = serByPre(tr); //使用前序遍历的方式序列化一颗二叉树 for (size_t i = 0; i < s.size(); i++) //使用一个队列将序列化的二叉树存贮起来 { if ('!' != s[i]) { qu.push(s[i]); } } cout << s << endl; TreeNode *tr1; reconPreOrder(tr1); //使用队列将前序遍历序列化的字符串反序列化,使之变成一颗二叉树 preOrder(tr1); //前序遍历反序列化后的二叉树,检验是否反序列化成功 cout << endl; return 0; }
判断一颗二叉树是否是平衡二叉树
#include<iostream> #include<string> #include<queue> #include<cmath> using namespace std; queue<char> qu; struct TreeNode { char data; TreeNode *lchild, *rchild; }; void createTree(TreeNode * &t) { char ch; cin >> ch; if ('#' == ch) { t = NULL; return; } t = new TreeNode; t->data = ch; createTree(t->lchild); createTree(t->rchild); } void preOrder(TreeNode *t) //递归前序遍历用于检验反序列化是否成功 { if (NULL == t) { return; } cout << t->data << " "; preOrder(t->lchild); preOrder(t->rchild); } struct bal_Trr //判断平衡二叉树函数的返回结构 { bool data; //是否是平衡二叉树 int h; //二叉树的高度 bal_Trr(bool t1, int t2) { this->data = t1; this->h = t2; } }; bal_Trr* judgeBtree(TreeNode *t) //判断是否是一颗平衡二叉树 { if (NULL == t) { return new bal_Trr(true, 0); } bal_Trr*l = judgeBtree(t->lchild); bal_Trr*r = judgeBtree(t->rchild); if (!l->data) { return new bal_Trr(false, 0); } if (!r->data) { return new bal_Trr(false, 0); } if (abs(l->h - r->h) > 1) { return new bal_Trr(false, 0); } return new bal_Trr(true, max(l->h, r->h) + 1); } int main() { TreeNode *tr; cout << "请使用前序遍历创建一颗二叉树\n"; createTree(tr); //使用前序遍历创建一颗二叉树 cout << endl; bal_Trr *a = judgeBtree(tr); //调用函数判断这颗二叉树是否是平衡二叉树 if (a->data) { cout << "平衡二叉树\n"; } else { cout << "不是平衡二叉树\n"; } return 0; }
搜索二叉树:左孩子比父节点小右孩子比父节点大的树成为搜索二叉树,搜索二叉树按照中序遍历是升序的,通常来说,搜索二叉树中每个结点的值是不相等的。
判断一棵树是否是搜索二叉树:将上面非递归的二叉树中序遍历稍微改动一下就可以了
判断一颗二叉树是否是完全二叉树,思路:使用层序遍历的方法来遍历二叉树,第一种情况,当右孩子存在左孩子不存在,不是完全二叉树,第二种情况,当一个结点的孩子不全的时候(只有左孩子,或者左右孩子都不存在),如果后续出现的结点不是叶子结点,则不是完全二叉树,当没有满足上面两中情况,那么就是完全二叉树
#include<iostream> #include<queue> using namespace std; struct TreeNode { char data; TreeNode *lchild, *rchild; }; void createTree(TreeNode * &t) { char ch; cin >> ch; if ('#' == ch) { t = NULL; return; } t = new TreeNode; t->data = ch; createTree(t->lchild); createTree(t->rchild); } void preOrder(TreeNode *t) //递归前序遍历用于检验反序列化是否成功 { if (NULL == t) { return; } cout << t->data << " "; preOrder(t->lchild); preOrder(t->rchild); } bool judgeByPreOrder(TreeNode *t) { queue<TreeNode *> qu; bool flag = false; //一个开关 qu.push(t); while (!qu.empty()) { TreeNode * item = qu.front(); qu.pop(); if (flag && (item->lchild || item->rchild)) //当开关开启后,后续的结点不是也结点就返回false { return false; } if (item->rchild && !item->lchild) //当右孩子存在左孩子不存在就返回false { return false; } if (item->lchild) { qu.push(item->lchild); } if (item->rchild) { qu.push(item->rchild); } if (!item->lchild || !item->rchild) { flag = true; //当第一次出现左右孩子都不存在或者左孩子存在右孩子不存在,就打开开关 } } return true; } int main() { TreeNode *tr; cout << "请使用前序遍历创建一颗二叉树\n"; createTree(tr); //使用前序遍历创建一颗二叉树 cout << endl; bool a = judgeByPreOrder(tr); if (a) { cout << "是完全二叉树\n"; } else { cout << "不是完全二叉树\n"; } return 0; }
已知一棵完全二叉树,求其节点的个数要求:时间复杂度低于O(N),N为这棵树的节点个
#include<iostream> #include<queue> using namespace std; struct TreeNode { char data; TreeNode *lchild, *rchild; }; void createTree(TreeNode * &t) { char ch; cin >> ch; if ('#' == ch) { t = NULL; return; } t = new TreeNode; t->data = ch; createTree(t->lchild); createTree(t->rchild); } int mostLeftLevel(TreeNode* node, int level) { while (NULL != node) { level++; node = node->lchild; } return level - 1; } int bs(TreeNode* node, int l, int h) { if (l == h) { return 1; } if (mostLeftLevel(node->rchild, l + 1) == h) { return (1 << (h - l)) + bs(node->rchild, l + 1, h); } else { return (1 << (h - l - 1)) + bs(node->lchild, l + 1, h); } } int nodeNum(TreeNode* head) //入口函数 { if (NULL == head) { return 0; } return bs(head, 1, mostLeftLevel(head, 1)); } int main() { TreeNode *tr; cout << "请使用前序遍历创建一颗二叉树\n"; createTree(tr); //使用前序遍历创建一颗二叉树 cout << endl; cout << nodeNum(tr) << endl; return 0; }