您的位置:首页 > 编程语言 > C语言/C++

二叉树学习小结(序列化和反序列化、二叉树遍历、二叉树镜像、二叉搜索树、二叉树子结构等)

2016-10-01 23:22 519 查看


二叉树

[cpp] view
plain copy

struct TreeNode {

int val;

struct TreeNode *left;

struct TreeNode *right;

TreeNode(int x) : val(x), left(NULL), right(NULL) {}

};


二叉树的序列化及反序列化


序列化二叉树

[cpp] view
plain copy

//==================================================

// 序列化二叉树

//==================================================

void serializeBTree(TreeNode* pRoot, ostream& out, char mark, char separator) {

if(NULL == pRoot) {

out << mark << separator;

return;

}

out << pRoot->val << separator;

serializeBTree(pRoot->left, out, mark, separator);

serializeBTree(pRoot->right, out, mark, separator);

}

/* 序列化二叉树

* pRoot:要序列化的二叉树

* mark:叶子节点下的 NULL 指针标记符(默认为 #)

* separator:分隔符(默认为空格)

*/

string Serialize(TreeNode *pRoot, char mark, char separator) {//【序列化二叉树】

ostringstream os;

if(NULL != pRoot) {

serializeBTree(pRoot, os, mark, separator);

}

return os.str();

}

反序列化二叉树

[cpp] view
plain copy

//==================================================

// 反序列化二叉树

//==================================================

// 使用流

bool readStream(istream& in, int& num, char mark, char separator) {

if(' ' == separator) {// 空格分割的情况

string str;

in >> str;

if("#" == str)

return false;

num = atoi(str.c_str());

return true;

} else {// 其他字符分割的情况

char ch;

string s = "";

in >> ch;

while(ch != separator) {

s += ch;

in >> ch;

}

if(s[0] != mark) {

num = atoi(s.c_str());

return true;

}

return false;

}

}

void deserializeBTree(TreeNode* &pRoot, istream& in, char mark, char separator) {// 使用流

int num;

if(readStream(in, num, mark, separator)) {

pRoot = new TreeNode(num);

deserializeBTree(pRoot->left, in, mark, separator);

deserializeBTree(pRoot->right, in, mark, separator);

}

}

// 使用 string

bool readString(string& str, int& num, char mark, char separator) {

string::size_type index = str.find_first_of(separator);

if(string::npos != index) {

string s = str.substr(0, index);

str = str.substr(index+1);

if(s[0] != mark) {

num = atoi(s.c_str());

return true;

}

}

return false;

}

void deserializeBTree(TreeNode* &pRoot, string& str, char mark, char separator) {// 使用 string

int num;

if(readString(str, num, mark, separator)) {

pRoot = new TreeNode(num);

deserializeBTree(pRoot->left, str, mark, separator);

deserializeBTree(pRoot->right, str, mark, separator);

}

}

/* 反序列化二叉树

* str:string 型的序列

* mark:叶子节点下的 NULL 指针标记符(默认为 #)

* separator:分隔符(默认为空格)

*/

TreeNode* Deserialize(string sequence, char mark, char separator){//【反序列化二叉树】

TreeNode* pRoot = NULL;

// istringstream in(sequence);

// deserializeBTree(pRoot, in, mark, separator);// 使用流

deserializeBTree(pRoot, sequence, mark, separator);// 使用 string

return pRoot;

}


二叉树的遍历(递归)

[cpp] view
plain copy

//==================================

// 二叉树遍历(递归)

//==================================

void PreorderTravel(TreeNode *pRoot) {// 【先序遍历(递归)】

if(pRoot) {

cout << pRoot->val << " ";

PreorderTravel(pRoot->left);

PreorderTravel(pRoot->right);

}

}

void InorderTravel(TreeNode *pRoot) {// 【中序遍历(递归)】

if(pRoot) {

InorderTravel(pRoot->left);

cout << pRoot->val << " ";

InorderTravel(pRoot->right);

}

}

void PostorderTravel(TreeNode *pRoot) {// 【后序遍历(递归)】

if(pRoot) {

PostorderTravel(pRoot->left);

PostorderTravel(pRoot->right);

cout << pRoot->val << " ";

}

}


二叉树的遍历(非递归)

[cpp] view
plain copy

//==================================

// 二叉树遍历(非递归)

//==================================

void PreorderNonRecursive(TreeNode *pRoot) { // 【前序遍历(非递归)】

stack<TreeNode*> s;

TreeNode *p = pRoot;

while(p != NULL || !s.empty()) {

while(p != NULL) {

cout << p->val << " ";// 根

s.push(p);

p = p->left;// 左

}

if(!s.empty()) {

p = s.top();

s.pop();

p = p->right;// 右

}

}

}

void InorderNonRecursive(TreeNode *pRoot) { // 【中序遍历(非递归)】

stack<TreeNode*> s;

TreeNode *p = pRoot;

while(p != NULL || !s.empty()) {

while(p != NULL) {

s.push(p);

p = p->left;// 左

}

if(!s.empty()) {

p = s.top();

cout << p->val << " ";// 根

s.pop();

p = p->right;// 右

}

}

}

/* 后序遍历:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点 p,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;

* 或者 p 存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。

* 若非上述两种情况,则将 p 的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。*/

void PostorderNonRecursive(TreeNode *pRoot) { // 【后序遍历(非递归)】

stack<TreeNode*> s;

TreeNode *cur;// 当前结点

TreeNode *pre = NULL;// 前一次访问的结点

s.push(pRoot);

while(!s.empty()) {

cur = s.top();

if((cur->left == NULL && cur->right == NULL) || // 如果当前结点没有孩子结点

(pre != NULL && (pre == cur->left || pre == cur->right))// 如果有孩子,因为孩子们是先入栈的,只要有一个孩子访问了,肯定是孩子们都被访问了(因为他们比当前结点先入栈的)

) {

cout << cur->val << " ";

s.pop();

pre = cur;

} else {

if(cur->right != NULL)// 右孩子先入栈,这样,每次取栈顶元素的时候,左孩子在右孩子前面被访问

s.push(cur->right);

if(cur->left != NULL)

s.push(cur->left);

}

}

}


按层打印二叉树


从上往下打印二叉树(层序遍历不分行)

[cpp] view
plain copy

vector<int> TravelFromTopToBottom(TreeNode *pRoot) {// 【从上往下打印二叉树】

vector<int> result;

if(NULL == pRoot) return result;

queue<TreeNode*> myQueue;

myQueue.push(pRoot);

while(!myQueue.empty()) {

TreeNode *p = myQueue.front();

result.push_back(p->val);

myQueue.pop();

if(p->left)

myQueue.push(p->left);

if(p->right)

myQueue.push(p->right);

}

return result;

}


把二叉树打印成多行(层序遍历分行)

[cpp] view
plain copy

vector<vector<int> > LevelTravel(TreeNode* pRoot) { // 【把二叉树打印成多行】

vector<vector<int> > result;

if(pRoot != NULL) {

queue<TreeNode*> q;

q.push(pRoot);

int levelWith = 0;

int n = 1;

vector<int> v;

while(!q.empty()) {

TreeNode* p = q.front();

v.push_back(p->val);

if(p->left) {

q.push(p->left);

++levelWith;

}

if(p->right) {

q.push(p->right);

++levelWith;

}

q.pop();

--n;

if(0 == n) {

result.push_back(v);

v.resize(0);

n = levelWith;

levelWith = 0;

}

}

}

return result;

}


按之字形顺序打印二叉树

[cpp] view
plain copy

vector<vector<int> > ZigzagTravel(TreeNode* pRoot) {// 【按之字形顺序打印二叉树】

vector<vector<int> > result;

if(NULL == pRoot) return result;

stack<TreeNode*> s1/*从右到左压入*/, s2/*从左到右压入*/;

s1.push(pRoot);

vector<int> vec;

while(!s1.empty() || !s2.empty()) {

while(!s1.empty()) {

TreeNode* node = s1.top();

vec.push_back(node->val);

if(node->left)

s2.push(node->left);

if(node->right)

s2.push(node->right);

s1.pop();

}

result.push_back(vec);

vec.resize(0);

while(!s2.empty()) {

TreeNode* node = s2.top();

vec.push_back(node->val);

if(node->right)

s1.push(node->right);

if(node->left)

s1.push(node->left);

s2.pop();

}

result.push_back(vec);

vec.resize(0);

}

return result;

}


重建二叉树


根据前序和中序重建二叉树

[cpp] view
plain copy

TreeNode* constrcutBT(const vector<int>& pre, vector<int>::size_type preLow, vector<int>::size_type preHigh,

const vector<int>& in, vector<int>::size_type inLow, vector<int>::size_type inHigh) {

// 前序的第一个是根

int rootValue = pre[preLow];

TreeNode* tree = new TreeNode(rootValue);

if(0 == preHigh-preLow && 0 == inHigh-inLow && pre[preLow] == in[inLow])

return tree;

// 在中序里面找到这个根的位置

vector<int>::size_type i = inLow;

for(; i != inHigh; i++) {

if(rootValue == in[i])

break;

}

if(i > inLow) {// 重建左子树

vector<int>::size_type in_L_Low = inLow, in_L_High = i - 1;// 左子树的中序起始点

vector<int>::size_type pre_L_Low = preLow + 1, pre_L_High = preLow + (i - inLow);// 左子树的前序起始点

tree->left = constrcutBT(pre, pre_L_Low, pre_L_High, in, in_L_Low, in_L_High);

}

if(i < inHigh) {// 重建右子树

vector<int>::size_type in_R_Low = i + 1, in_R_High = inHigh;// 右子树的中序起始点

vector<int>::size_type pre_R_Low = preLow + (i - inLow) + 1, pre_R_High = preHigh;// 右子树的前序起始点

tree->right = constrcutBT(pre, pre_R_Low, pre_R_High, in, in_R_Low, in_R_High);

}

return tree;

}

struct TreeNode* ReConstructBinaryTree(vector<int> pre, vector<int> in) {// 【根据前序和中序重建二叉树】

if(pre.empty() || in.empty() || pre.size() != in.size())

return NULL;

return constrcutBT(pre, 0, pre.size()-1, in, 0, in.size()-1);

}


判断二叉树是否是对称二叉树

[cpp] view
plain copy

bool isSymm(TreeNode* pRoot1, TreeNode* pRoot2) {

if(NULL == pRoot1 && NULL == pRoot2) return true;

if(NULL == pRoot1 || NULL == pRoot2) return false;

if(pRoot1->val != pRoot2->val) return false;

return (isSymm(pRoot1->left, pRoot2->right) && isSymm(pRoot1->right, pRoot2->left));

}

bool IsSymmetrical(TreeNode* pRoot) {// 【对称二叉树】

return isSymm(pRoot, pRoot);

}


二叉树的镜像(对换左右子树)

[cpp] view
plain copy

void Mirror(TreeNode *pRoot) {// 【二叉树的镜像(对换左右子树)】

if(pRoot != NULL) {

TreeNode *p = pRoot->left;

pRoot->left = pRoot->right;

pRoot->right = p;

Mirror(pRoot->left);

Mirror(pRoot->right);

}

}


判断树的子结构

[cpp] view
plain copy

bool hasST(TreeNode *pRoot1, TreeNode *pRoot2) {// 判断树1中以此节点为根节点的子树是不是包含数2一样的结构

if(NULL == pRoot2) return true;// 递归终止条件

if(NULL == pRoot1) return false;

if(pRoot1->val != pRoot2->val) return false;

return (hasST(pRoot1->left, pRoot2->left) && hasST(pRoot1->right, pRoot2->right));

}

bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {// 【判断树 pRoot2 是不是树 pRoot1 的子结构】

bool flag = false;

if(pRoot1 != NULL && pRoot2 != NULL) {

if(pRoot1->val == pRoot2->val)// 在树1中找到和树2的根节点的值一样的节点

flag = hasST(pRoot1, pRoot2);// 判断树1中以此节点为根节点的子树是不是包含数2一样的结构

if(!flag)

flag = HasSubtree(pRoot1->left, pRoot2);// 在左子树中查找

if(!flag)

flag = HasSubtree(pRoot1->right, pRoot2);// 在右子树中查找

}

return flag;

}


判断二叉树是否是平衡二叉树

[cpp] view
plain copy

bool isBalanced(TreeNode* pRoot, int& depth) {

if(!pRoot) {

depth = 0;

return true;

}

int leftDepth, rightDepth;

// 如果左右子树是平衡的,则计算当前节点作为根节点的树是否是平衡的

if(isBalanced(pRoot->left, leftDepth) && isBalanced(pRoot->right, rightDepth)) {

int d = abs(leftDepth - rightDepth);

if(d <= 1) {

depth = leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;

return true;

}

}

return false;

}

bool IsBalanced(TreeNode* pRoot) {// 【判断二叉树是否是平衡二叉树】

// // 方案一

// if(!pRoot)

// return true;

// int leftDepth = TreeDepth(pRoot->left);// 计算左子树深度

// int rightDepth = TreeDepth(pRoot->right);// 计算右子树深度

// int d = abs(leftDepth - rightDepth);// 左右子树深度差

// if(d > 1)// 如果深度差超过 1 则不是平衡二叉树

// return false;

// return IsBalanced_Solution(pRoot->left) && IsBalanced_Solution(pRoot->right);

// 方案二(方案一中一个结点会被重复遍历多次,效率不高。这里方案二采用后序遍历的方式,每个节点只访问一次)

int depth;

return isBalanced(pRoot, depth);

}


二叉树的深度

[cpp] view
plain copy

//void getTreeDepth(TreeNode* p, int& depth, int& maxDepth) {

// if(p) {

// depth++;

// if(!p->left && !p->right) {// 如果到了叶子节点,则更新深度值

// if(depth > maxDepth)

// maxDepth = depth;

// }

// else {

// if(p->left) {

// getTreeDepth(p->left, depth, maxDepth);

// depth--;

// }

// if(p->right)

// getTreeDepth(p->right, depth, maxDepth);

// }

// }

//}

//int TreeDepth(TreeNode* pRoot) {//【二叉树的深度】方案一

// int depth = 0, maxDepth = 0;

// getTreeDepth(pRoot, depth, maxDepth);

// return maxDepth;

//}

int TreeDepth(TreeNode* pRoot) {//【二叉树的深度】方案二

if(!pRoot) return 0;

int leftDepth = TreeDepth(pRoot->left);// 计算左子树深度

int rightDepth = TreeDepth(pRoot->right);// 计算右子树深度

return (leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1);// 树的深度为较大者深度 + 1

}


二叉树中和为某一值的路径

[cpp] view
plain copy

void findPath(TreeNode* root, int& curSum, const int& expectNumber, vector<int>& path, vector<vector<int> >& paths) {

if(root) {

curSum += root->val;

path.push_back(root->val);

if(NULL == root->left && NULL == root->right && curSum == expectNumber)

paths.push_back(path);

if(root->left)

findPath(root->left, curSum, expectNumber, path, paths);

if(root->right)

findPath(root->right, curSum, expectNumber, path, paths);

curSum -= root->val;

path.pop_back();

}

}

vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {// 【二叉树中和为某一值的路径】

vector<vector<int> > paths;

if(NULL == root) return paths;

int curSum = 0;

vector<int> path;

findPath(root, curSum, expectNumber, path, paths);

return paths;

}


二叉搜索树


判断一个序列是不是二叉搜索树的后序遍历序列

[cpp] view
plain copy

bool VerifySquenceOfBST(vector<int> sequence) {// 【判断一个序列是不是二叉搜索树的后序遍历序列】

if(sequence.empty()) return false;

int rootValue = sequence[sequence.size()-1];// 根节点

vector<int>::size_type length = 0, i = 0;

for(; i < sequence.size()-1; i++)// 寻找根节点左右子树分割点

if(sequence[i] > rootValue)

break;

length = i;// 左子树节点数

for(++i; i < sequence.size()-1; i++)// 判断右子树节点中,是否有小于根节点值的

if(sequence[i] < rootValue)

return false;

bool L_flag = true, R_flag = true;

if(length > 0) {// 递归判断左子树

vector<int> vecL(sequence.begin(), sequence.begin()+length);

L_flag = VerifySquenceOfBST(vecL);

}

if(length < sequence.size()-1) {// 递归判断右子树

vector<int> vecR(sequence.begin()+length, sequence.end()-1);

R_flag = VerifySquenceOfBST(vecR);

}

return (L_flag && R_flag);

}


二叉搜索树转为双向链表

[cpp] view
plain copy

void convertTree2List(TreeNode* p, TreeNode* &pList) {

if(p) {

if(p->left)

convertTree2List(p->left, pList);// 转换左子树

p->left = pList;// 将此根节点左边指向双向链表的最右边

if(pList)

pList->right = p;// 双向链表的最右边的节点指向此根节点

pList = p;// 更新 pList 指向双向链表的最右边

if(p->right)

convertTree2List(p->right, pList);// 转换右子树

}

}

TreeNode* Convert(TreeNode* pRootOfTree) {// 【二叉搜索树转为双向链表】

if(pRootOfTree) return NULL;

TreeNode *pList/*指向双向链表最右边那个节点*/ = NULL, *pListHead/*双向链表*/ = NULL;

convertTree2List(pRootOfTree, pList);

pListHead = pList;

while(pListHead && pListHead->left)// 因为 pList 指向的是双向链表的最右边,所以反向遍历到最左边得到表头

pListHead = pListHead->left;

return pListHead;

}


二叉搜索树的第 k 个结点

给定一颗二叉搜索树,请找出其中的第k小的结点。例如, 5 3 2 # # 4 # # 7 6 # # 8 # #,按结点数值大小顺序第三个结点的值为 4

[cpp] view
plain copy

bool FindKthOfBST(TreeNode* pRoot, int& k, int& val) {//【查找二叉搜索树的第 k 小的结点,若找到返回 true,并用 val 存放这个结点的值】

// 用中序遍历即可从小到大访问二叉搜索树的结点

bool isFind = false;

if(pRoot != NULL) {

// 左

isFind = FindKthOfBST(pRoot->left, k, val);

// 根

k--;

if(0 == k) {

val = pRoot->val;

isFind = true;

}

// 右

if(!isFind)

isFind = FindKthOfBST(pRoot->right, k, val);

}

return isFind;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐