二叉树
分别用递归和非递归方式实现二叉树先序、中序和后序遍历
代码
包含测试用例,
#include<iostream>
#include<stack>
#include<vector>
using namespace std;
struct treeNode {
int val;
treeNode* left;
treeNode* right;
treeNode(int value)
{
val = value;
}
};
treeNode* createTree(int a[], int len)
{
treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
int i;
for (i = 0; i < len; i++)
{
tree[i].val = a[i];
tree[i].left = NULL;
tree[i].right = NULL;
}
for (i = 0; i <= len / 2 - 1; i++)
{
if (2 * i + 1 <= len - 1)
tree[i].left = &tree[2 * i + 1];
if (2 * i + 2 <= len - 1)
tree[i].right = &tree[2 * i + 2];
}
return tree;
}
void preOrderRecur(treeNode* root)
{
if (root == NULL)
return;
cout << root->val;
preOrderRecur(root->left);
preOrderRecur(root->right);
}
void inOrderRecur(treeNode* root)
{
if (root == NULL)
return;
inOrderRecur(root->left);
cout << root->val;
inOrderRecur(root->right);
}
void postOrderRecur(treeNode* root)
{
if (root == NULL)
return;
postOrderRecur(root->left);
postOrderRecur(root->right);
cout << root->val;
}
void preOrderNoRecur(treeNode* root)
{
if (root == NULL)
return;
stack<treeNode*> treeS;
treeNode* cur = root;
treeS.push(cur);
while (!treeS.empty())
{
treeNode* tmp = treeS.top();
cout << tmp->val;
treeS.pop();
if (tmp->right != NULL)
treeS.push(tmp->right);
if (tmp->left != NULL)
treeS.push(tmp->left);
}
cout << endl;
}
void inOrderNoRecur(treeNode* root)
{
if (root == NULL)
return;
stack<treeNode*> treeS;
treeNode* cur = root;
while (!treeS.empty() || cur != NULL)
{
if (cur != NULL)
{
treeS.push(cur);
cur = cur->left;
}
else
{
treeNode* tmp = treeS.top();
treeS.pop();
cout << tmp->val;
cur = tmp->right;
}
}
cout << endl;
}
//非递归实现二叉树的后序遍历的过程稍微复杂,用到两个栈
void postOrderNoRecur(treeNode* root)
{
if (root == NULL)
return;
treeNode* cur = root;
stack<treeNode*> s1;
stack<treeNode*> s2;
s1.push(root);
while (!s1.empty())
{
treeNode* tmp = s1.top();
s1.pop();
s2.push(tmp);
if (tmp->left != NULL)
s1.push(tmp->left);
if (tmp->right != NULL)
s1.push(tmp->right);
}
while (!s2.empty())
{
treeNode* tmp1 = s2.top();
s2.pop();
cout << tmp1->val;
}
cout << endl;
}
int main()
{
int input[] = { 1, 2, 3, 4, 5, 6, 7 };
int len = 7;
treeNode* root = createTree(input, len);
preOrderRecur(root);
preOrderNoRecur(root);
cout << "========================" << endl;
inOrderRecur(root);
inOrderNoRecur(root);
cout << "========================" << endl;
postOrderRecur(root);
postOrderNoRecur(root);
getchar();
return 0;
}
二叉树的序列化和反序列化
题目
二叉树被记录为文件的过程叫做二叉树的序列化,通过文件内容重建原来二叉树的过程叫作二叉树的反序列化。给定一颗二叉树的头节点head,并已知二叉树节点值类型为32位整型。设计一种二叉树序列化和反序列化方案
代码
用‘!’表示一个节点的结束,‘#!’表示一直为NULL的节点。
#include<iostream>
#include<vector>
#include<string>
#include<queue>
using namespace std;
struct treeNode {
int val;
treeNode* left;
treeNode* right;
treeNode(int value)
{
val = value;
}
};
treeNode* createTree(int a[], int len)
{
treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
int i;
for (i = 0; i < len; i++)
{
tree[i].val = a[i];
tree[i].left = NULL;
tree[i].right = NULL;
}
for (i = 0; i <= len / 2 - 1; i++)
{
if (2 * i + 1 <= len - 1)
tree[i].left = &tree[2 * i + 1];
if (2 * i + 2 <= len - 1)
tree[i].right = &tree[2 * i + 2];
}
return tree;
}
string serialize(treeNode* root)
{
string s;
if (root == NULL)
{
return "#!";
}
s += to_string(root->val) + "!";
s += serialize(root->left);
s += serialize(root->right);
return s;
}
//反序列化
treeNode* deSerializeHelper(char **str)
{
if (**str == '#')
{
(*str)++;
(*str)++;
return NULL;
}
int num = 0;
while (**str != '\0' && **str != '!')
{
num = num * 10 + (**str - '0');
(*str)++;
}
treeNode* root = new treeNode(num);
if (**str == '\0')
return root;
else
(*str)++;
root->left = deSerializeHelper(str);
root->right = deSerializeHelper(str);
return root;
}
treeNode* deSerialize(string str)
{
if (str == "#!")
return NULL;
int len = str.size();
char* s = (char*)malloc(sizeof(char));
memcpy(s, str.c_str(), sizeof(char) * len);
treeNode* root = deSerializeHelper(&s);
return root;
}
//判断两个树是否相等
bool isEqual(treeNode* root1, treeNode* root2)
{
if (root1 == NULL && root2 == NULL)
return true;
if (root1 == NULL && root2 != NULL)
return false;
if (root1 != NULL && root2 == NULL)
return false;
if (root1->val != root2->val)
return false;
else
return isEqual(root1->left, root2->left) && isEqual(root1->right, root2->right);
}
int main()
{
int input[] = { 1, 2, 3, 4, 5, 6 };
int len = 6;
treeNode* root = createTree(input, len);
string res = serialize(root);
cout << res << endl;
treeNode* root1 = deSerialize(res);
bool res1 = isEqual(root, root1);
if (res1)
cout << "Two tree is the same!" << endl;
else
cout << "Two tree is not same! May be serial or deserial has a problem" << endl;
getchar();
return 0;
}
遍历二叉树的神级方法(Morris遍历)
题目
给定一颗二叉树的头节点head,完成二叉树的先序、中序和后序遍历。如果二叉树节点数为N,要求时间复杂度为O(N),额外空间复杂度为O(1)。
代码
详细的解释过程请参考原书,不再多说
#include<iostream>
using namespace std;
struct treeNode {
int val;
treeNode* left;
treeNode* right;
treeNode(int value)
{
val = value;
}
};
treeNode* createTree(int a[], int len)
{
treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
int i;
for (i = 0; i < len; i++)
{
tree[i].val = a[i];
tree[i].left = NULL;
tree[i].right = NULL;
}
for (i = 0; i <= len / 2 - 1; i++)
{
if (2 * i + 1 <= len - 1)
tree[i].left = &tree[2 * i + 1];
if (2 * i + 2 <= len - 1)
tree[i].right = &tree[2 * i + 2];
}
return tree;
}
//morris中序遍历
void morrisIn(treeNode* root)
{
if (root == NULL)
return;
treeNode* cur1 = root;
treeNode* cur2 = NULL;
while (cur1 != NULL)
{
cur2 = cur1->left;
if (cur2 != NULL)
{
while (cur2->right != NULL && cur2->right != cur1)
cur2 = cur2->right;
if (cur2->right == NULL)
{
cur2->right = cur1;
cur1 = cur1->left;
continue;
}
else
cur2->right = NULL;
}
cout << cur1->val << " ";
cur1 = cur1->right;
}
cout << endl;
}
/*第一步将每个节点左子树上的最右节点链接到当前节点,第二次
打印之前先将节点进行恢复,这样可以实现O(1)的空间复杂度,没有使用
额外的数据结构*/
//morris先序遍历的情况
//先序遍历是中序遍历的简单改写,只是打印节点的时机发生了改变
void morrisPre(treeNode* root)
{
if (root == NULL)
return;
treeNode* cur1 = root;
treeNode* cur2 = NULL;
while (cur1 != NULL)
{
cur2 = cur1->left;
if (cur2 != NULL)
{
while (cur2->right != NULL && cur2->right != cur1)
cur2 = cur2->right;
if (cur2->right == NULL)
{
cur2->right = cur1;
cout << cur1->val << " ";
cur1 = cur1->left;
continue;
}
else
cur2->right = NULL;
}
else
cout << cur1->val << " ";
cur1 = cur1->right;
}
cout << endl;
}
/*morris后序遍历略微复杂,实话说后序遍历的逻辑还没有理特别清楚,只是简单地改写了过来*/
treeNode* reverseEdge(treeNode* from)
{
treeNode* pre = NULL;
treeNode* next = NULL;
while (from != NULL)
{
next = from->right;
from->right = pre;
pre = from;
from = next;
}
return pre;
}
void printEdge(treeNode* head)
{
treeNode* tail = reverseEdge(head);
treeNode* cur = tail;
while (cur != NULL)
{
cout << cur->val << " ";
cur = cur->right;
}
reverseEdge(tail);
}
void morrisPos(treeNode* head)
{
if (head == NULL)
return;
treeNode* cur1 = head;
treeNode* cur2 = NULL;
while (cur1 != NULL)
{
cur2 = cur1->left;
if (cur2 != NULL)
{
while (cur2->right != NULL && cur2->right != cur1)
cur2 = cur2->right;
if (cur2->right == NULL)
{
cur2->right = cur1;
cur1 = cur1->left;
continue;
}
else
{
cur2->right = NULL;
printEdge(cur1->left);
}
}
cur1 = cur1->right;
}
printEdge(head);
cout << endl;
}
int main()
{
int input[] = { 1, 2, 3, 4, 5, 6, 7 };
int len = 7;
treeNode* root = createTree(input, len);
morrisIn(root);
morrisPre(root);
morrisPos(root);
getchar();
return 0;
}
在二叉树中找到累加和为指定值的最长路径长度
题目
给定一颗二叉树的头节点和一个32位整数sum,二叉树节点值类型为整型,求累加和为sum的最长路径长度。路径是指从某节点往下,每次最多选择一个孩子节点或者不选所形成的节点链。具体实例请参考原书籍。(无需考虑节点相加溢出的问题)
代码
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
struct treeNode {
int val;
treeNode* left;
treeNode* right;
treeNode(int value):val(value), left(NULL), right(NULL){}
};
treeNode* createTree(int a[], int len)
{
treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
int i;
for (i = 0; i < len; i++)
{
tree[i].val = a[i];
tree[i].left = NULL;
tree[i].right = NULL;
}
for (i = 0; i <= len / 2 - 1; i++)
{
if (2 * i + 1 <= len - 1)
tree[i].left = &tree[2 * i + 1];
if (2 * i + 2 <= len - 1)
tree[i].right = &tree[2 * i + 2];
}
return tree;
}
int preOrder(treeNode* head, int sum, int preSum, int level, int maxLen, map<int, int> &sumMap)
{
if (head == NULL)
return maxLen;
int curSum = preSum + head->val;
if (sumMap.find(curSum) == sumMap.end())
sumMap.insert(pair<int, int>(curSum, level));
if (sumMap.find(curSum - sum) != sumMap.end())
maxLen = max(level - sumMap[curSum - sum], maxLen);
maxLen = preOrder(head->left, sum, curSum, level + 1, maxLen, sumMap);
maxLen = preOrder(head->right, sum, curSum, level + 1, maxLen, sumMap);
if (level == sumMap[curSum])
sumMap.erase(curSum);
return maxLen;
}
int getMaxLen(treeNode* head, int sum)
{
map<int, int>mp;
mp[0] = 0;
return preOrder(head, sum, 0, 1, 0, mp);
}
int main()
{
int input[] = { -3, 3, -9, 1, 0, 2, 1, 7, 5, 1, 6 };
int len = 11;
treeNode* root = createTree(input, len);
int sum = 6;
int res = getMaxLen(root, sum);
cout << res << endl;
getchar();
return 0;
}
二叉树的按层打印与ZigZag打印
题目
给定一颗二叉树头节点head,分别实现按层打印与ZigZag打印二叉树的函数
代码
#include<iostream>
#include<stack>
#include<queue>
#include<string>
using namespace std;
struct treeNode {
int val;
treeNode* left;
treeNode* right;
treeNode(int value) :val(value), left(NULL), right(NULL){}
};
treeNode* createTree(int a[], int len)
{
treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
int i;
for (i = 0; i < len; i++)
{
tree[i].val = a[i];
tree[i].left = NULL;
tree[i].right = NULL;
}
for (i = 0; i <= len / 2 - 1; i++)
{
if (2 * i + 1 <= len - 1)
tree[i].left = &tree[2 * i + 1];
if (2 * i + 2 <= len - 1)
tree[i].right = &tree[2 * i + 2];
}
return tree;
}
/*按层打印*/
void printByLevel(treeNode* head)
{
if (head == NULL)
return;
queue<treeNode*> tq;
tq.push(head);
treeNode* cur = NULL;
int len = 0;
int level = 1;
while (!tq.empty())
{
len = tq.size();
cout << "level " << level << " :";
for (int i = 0; i < len; i++)
{
cur = tq.front();
cout << cur->val;
tq.pop();
if (cur->left != NULL)
tq.push(cur->left);
if (cur->right != NULL)
tq.push(cur->right);
}
cout << endl;
level++;
}
}
void printByZigZag(treeNode* head)
{
if (head == NULL)
return;
stack<treeNode*> treeO, treeE;
int level = 1;
treeO.push(head);
treeNode* tmp = NULL;
while (!treeO.empty() || !treeE.empty())
{
if (!treeO.empty())
{
while (!treeO.empty())
{
tmp = treeO.top();
treeO.pop();
cout << tmp->val << " ";
if (tmp->left != NULL)
treeE.push(tmp->left);
if (tmp->right != NULL)
treeE.push(tmp->right);
}
cout << endl;
}
else if (!treeE.empty())
{
while (!treeE.empty())
{
tmp = treeE.top();
treeE.pop();
cout << tmp->val << " ";
if (tmp->right != NULL)
treeO.push(tmp->right);
if (tmp->left != NULL)
treeO.push(tmp->left);
}
cout << endl;
}
}
}
void printLevelAndOrientation(int level, bool lr)
{
cout << "Level " + to_string(level) + " from ";
cout << lr ? "left to right" : "right to left";
}
void printByDeque(treeNode* root)
{
if (root == NULL)
return;
deque<treeNode*> dq;
int level = 1;
bool lr = true;
treeNode* last = root;
treeNode* nLast = NULL;
dq.push_front(root);
while (!dq.empty())
{
if (lr)
{
root = dq.front();
dq.pop_front();
if (root->left != NULL)
{
nLast = nLast == NULL ? root->left : nLast;
dq.push_back(root->left);
}
if (root->right != NULL)
{
nLast = nLast == NULL ? root->right : nLast;
dq.push_back(root->right);
}
}
else
{
root = dq.back();
dq.pop_back();
if (root->right != NULL)
{
nLast = nLast == NULL ? root->right : nLast;
dq.push_front(root->right);
}
if (root->left != NULL)
{
nLast = nLast == NULL ? root->left : nLast;
dq.push_front(root->left);
}
}
cout << root->val << " ";
if (root == last && !dq.empty())
{
lr = !lr;
last = nLast;
nLast = NULL;
cout << endl;
printLevelAndOrientation(level++, lr);
}
}
cout << endl;
}
int main()
{
int input[] = { 1, 2, 3, 4, 5, 6, 7 };
int len = 7;
treeNode* root = createTree(input, len);
printByLevel(root);
printByZigZag(root);
printByDeque(root);
getchar();
return 0;
}