二叉树问题之五

分别用递归和非递归方式实现二叉树先序、中序和后序遍历

代码

包含测试用例,

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值