二叉树的结构
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);
}

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

被折叠的 条评论
为什么被折叠?



