二叉树的结点个数
1、如果二叉树为空,节点个数为0
2、不为空,节点个数 = 左子树节点个数 + 右子树节点个数 + 1
/*
二叉树的节点个数
1、如果二叉树为空,节点个数为0
2、不为空,节点个数 = 左子树节点个数 + 右子树节点个数 + 1
*/
int GetTreeNum(pTree T)
{
if(T == NULL)
return 0;
return GetTreeNum(T->Left) + GetTreeNum(T->Right) + 1;
}
二叉树的深度
1、如果二叉树为空,深度为0
2、不为空,深度为 = max(左子树深度,右子树深度) + 1
/*
二叉树的深度
1、如果二叉树为空,深度为0
2、不为空,深度为 = max(左子树深度,右子树深度) + 1
*/
int GetTreeDepth(pTree T)
{
if(T == NULL)
return 0;
return max(GetTreeDepth(T->Left), GetTreeDepth(T->Right)) + 1;
}
二叉树的遍历
前序遍历递归实现
1、二叉树为空,返回
2、不为空,先访问根节点,然后遍历左子树,最后遍历右子树
/*
前序遍历(递归解法)
1、二叉树为空,返回
2、不为空,先访问根节点,然后遍历左子树,最后遍历右子树
*/
void PreOrderTraverse(pTree T)
{
if(T == NULL)
return;
cout << T->value;
PreOrderTraverse(T->Left);
PreOrderTraverse(T->Right);
}
前序遍历非递归实现(栈模拟)
先访问,再入栈;
1、如果T非空,访问栈顶元素,把T入栈,T指向左儿子。。
2、如果T为空,说明已经向左走到尽头了,弹出当前栈顶元素,T指向右儿子。
/*
前序遍历(非递归解法——栈模拟递归实现)
先访问,再入栈;
1、如果T非空,访问栈顶元素,把T入栈,T指向左儿子。。
2、如果T为空,说明已经向左走到尽头了,弹出当前栈顶元素,T指向右儿子。
*/
void PreOrderTraverse2(pTree T)
{
if(T == NULL)
return;
stack<pTree> Stk;
while(T || !Stk.empty())
{
if(T)
{
cout << T->value;
Stk.push(T);
T = T->Left;
}
else
{
T = Stk.top();
Stk.pop();
T = T->Right;
}
}
}
中序遍历递归实现
1、二叉树为空,返回
2、不为空,先遍历左子树,然后访问根节点,最后遍历右子树
/*
中序遍历(递归解法)
1、二叉树为空,返回
2、不为空,先遍历左子树,然后访问根节点,最后遍历右子树
*/
void InOrderTraverse(pTree T)
{
if(T == NULL)
return;
InOrderTraverse(T->Left);
cout << T->value;
InOrderTraverse(T->Right);
}
中序遍历非递归实现(栈模拟)
先入栈,后访问;
1、如果T非空,把T入栈,T指向左儿子。。
2、如果T为空,说明已经向左走到尽头了,弹出当前栈顶元素,进行访问,然后T指向右儿子。
/*
中序遍历(非递归解法——栈模拟递归实现)
先入栈,后访问;
1、如果T非空,把T入栈,T指向左儿子。。
2、如果T为空,说明已经向左走到尽头了,弹出当前栈顶元素,进行访问,然后T指向右儿子。
*/
void InOrderTraverse2(pTree T)
{
if(T == NULL)
return;
stack<pTree> Stk;
while(T || !Stk.empty())
{
if(T)
{
Stk.push(T);
T = T->Left;
}
else
{
T = Stk.top();
Stk.pop();
cout << T->value;
T = T->Right;
}
}
}
后序遍历递归实现
1、二叉树为空,返回
2、不为空,先遍历左子树,然后遍历右子树,最后访问根节点
/*
后序遍历(递归解法)
1、二叉树为空,返回
2、不为空,先遍历左子树,然后遍历右子树,最后访问根节点
*/
void PostOrderTraverse(pTree T)
{
if(T == NULL)
return;
PostOrderTraverse(T->Left);
PostOrderTraverse(T->Right);
cout << T->value;
}
后序遍历非递归实现(双栈模拟)
采用两个栈来实现,不过就是先压入当前节点的左子树,后压入当前节点的右子树。得到的顺序是根节点-右子树-左子树,刚好是后序遍历的逆序,所以再利用一个栈解决就可以倒过来。
/*
后序遍历(非递归解法)
采用两个栈来实现,不过就是先压入当前节点的左子树,后压入当前节点的右子树。
得到的顺序是根节点-右子树-左子树,刚好是后序遍历的逆序,所以再利用一个栈解决就可以倒过来。
*/
void PostOrderTraverse2(pTree T)
{
if(T == NULL)
return;
stack<pTree> Stk1,Stk2;
Stk1.push(T);
while(!Stk1.empty())
{
pTree p = Stk1.top();
Stk1.pop();
Stk2.push(p);
if(p->Left)
Stk1.push(p->Left);
if(p->Right)
Stk1.push(p->Right);
}
while(!Stk2.empty())
{
cout << Stk2.top()->value;
Stk2.pop();
}
}
层序遍历队列实现
层序遍历就是从上到下从左到右访问树的节点。采用FIFO(先进先出)的数据结构-队列先将根节点入队,当队列不为空时,弹出一个节点,然后访问,若左子树或右子树不为空,将其入队
/*
层序遍历(队列)
层序遍历就是从上到下从左到右访问树的节点。采用FIFO(先进先出)的数据结构-队列
先将根节点入队,当队列不为空时,弹出一个节点,然后访问,若左子树或右子树不为空,
将其入队
*/
void LevelTraverse(pTree T)
{
if(T == NULL)
return;
queue<pTree> que;
que.push(T);
while(!que.empty())
{
pTree p = que.front();
que.pop();
cout << p->value;
if(p->Left)
que.push(p->Left);
if(p->Right)
que.push(p->Right);
}
}
二叉搜索树转换双向链表
http://blog.csdn.net/zwhlxl/article/details/46622981
二叉树第K层的结点个数
递归解法:
1、如果二叉树为空且k<1 则返回0;
2、如果二叉树不为空且k=1,返回1;
3、如果二叉树不为空且k>1,返回左子树中k-1层的结点个数与右子树中K-1层的结点个数之和
/*
二叉树第K层的结点个数
1、如果二叉树为空且k<1 则返回0;
2、如果二叉树不为空且k=1,返回1;
3、如果二叉树不为空且k>1,返回左子树中k-1层的结点个数与右子树中K-1层的结点个数之和
*/
int GetKthLevelNode(pTree T, int k)
{
if(T == NULL || k < 0)
return 0;
if(k == 1)
return 1;
int leftnum = GetKthLevelNode(T->Left, k - 1);
int rightnum = GetKthLevelNode(T->Right, k - 1);
return leftnum + rightnum;
}
非递归解法:
利用队列解决
int GetKthLevelNode2(pTree T, int k)
{
if(T == NULL || k < 0)
return 0;
int curLevel = 0;
int curLevelNode = 0;
queue<pTree> que;
que.push(T);
while(!que.empty())
{
curLevel ++;
curLevelNode = que.size(); // 当前层的结点个数
if(curLevel == k) // 如果当前层数等于所求的层数,跳出循环
break;
int cntNode = 0 ;
while(cntNode < curLevelNode) //如果当前层数还没到求的层数,将当前层结点弹出,下一层结点入栈
{
cntNode ++;
T = que.front();
que.pop();
if(T->Left != NULL)
que.push(T->Left);
if(T->Right != NULL)
que.push(T->Right);
}
}
while(!que.empty())
que.pop();
if(curLevel == k)
return curLevelNode;
return 0; //k 值大于树的深度,返回0
}
寻找二叉树两个节点的最低公共祖先
http://www.acmerblog.com/lca-lowest-common-ancestor-5574.html
#include <iostream>
#include <vector>
using namespace std;
struct Node
{
int key;
struct Node *left;
struct Node *right;
};
Node* newNode(int k)
{
Node* tmp = new Node;
tmp->key = k;
tmp->left = NULL;
tmp->right = NULL;
}
bool FindPath(Node* root, vector<int> &path, int key)
{
if(root == NULL)
return false;
path.push_back(root->key);
if(root->key == key)
return true;
bool found = (FindPath(root->left, path, key) | FindPath(root->right, path, key));
/*
bool found = false;
found = FindPath(root->left, path, key);
if(!found)
found = FindPath(root->right, path, key);
*/
if(!found)
path.pop_back();
return found;
}
int FindLCA(Node* root, int key1, int key2)
{
vector<int> path1, path2;
int ans;
bool found1 = FindPath(root, path1, key1);
bool found2 = FindPath(root, path2, key2);
if(found1 && found2)
{
for(int i = 0; i < path1.size(); i ++)
{
if(path1[i] != path2[i])
break;
else
ans = path1[i];
}
return ans;
}
return -1;
}
int main(int argc, char const *argv[])
{
Node* Tree = newNode(1);
Tree->left = newNode(2);
Tree->right = newNode(3);
Tree->left->left = newNode(4);
Tree->left->right = newNode(5);
Tree->right->left = newNode(6);
Tree->right->right= newNode(7);
cout << "LCA(4,5)" << FindLCA(Tree, 4, 5) << endl;
cout << "LCA(4,6)" << FindLCA(Tree, 4, 6) << endl;
return 0;
}
测试程序
分别有求二叉树的节点个数,深度,和前序,中序,后序的递归和非递归实现
#include <iostream>
#include <stack>
#include <queue>
/*
A
B C
D E F G
H I J
K
*/
using namespace std;
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef char ElementType;
typedef struct TreeNode
{
ElementType value;
struct TreeNode *Left;
struct TreeNode *Right;
}TreeNode, *pTree;
int index = 0;
char str[] = "ABDH#K###E##CFI###G#J##";
void DeleteTree(pTree *T)
{
if(*T)
{
if((*T)->Left)
DeleteTree(&(*T)->Left);
if((*T)->Right)
DeleteTree(&(*T)->Right);
free(*T);
*T = NULL;
}
}
void CreatTree(pTree *T)
{
ElementType ch;
ch = str[index ++];
if(ch == '#')
*T = NULL;
else
{
//(pTree) *T = new TreeNode;
*T = (pTree)malloc(sizeof(TreeNode));
if(*T == NULL)
exit(ERROR);
(*T)->value = ch;
CreatTree(&(*T)->Left);
CreatTree(&(*T)->Right);
}
}
/*
二叉树的节点个数
1、如果二叉树为空,节点个数为0
2、不为空,节点个数 = 左子树节点个数 + 右子树节点个数 + 1
*/
int GetTreeNum(pTree T)
{
if(T == NULL)
return 0;
return GetTreeNum(T->Left) + GetTreeNum(T->Right) + 1;
}
/*
二叉树的深度
1、如果二叉树为空,深度为0
2、不为空,深度为 = max(左子树深度,右子树深度) + 1
*/
int GetTreeDepth(pTree T)
{
if(T == NULL)
return 0;
return max(GetTreeDepth(T->Left), GetTreeDepth(T->Right)) + 1;
}
/*
前序遍历(递归解法)
1、二叉树为空,返回
2、不为空,先访问根节点,然后遍历左子树,最后遍历右子树
*/
void PreOrderTraverse(pTree T)
{
if(T == NULL)
return;
cout << T->value;
PreOrderTraverse(T->Left);
PreOrderTraverse(T->Right);
}
/*
中序遍历(递归解法)
1、二叉树为空,返回
2、不为空,先遍历左子树,然后访问根节点,最后遍历右子树
*/
void InOrderTraverse(pTree T)
{
if(T == NULL)
return;
InOrderTraverse(T->Left);
cout << T->value;
InOrderTraverse(T->Right);
}
/*
后序遍历(递归解法)
1、二叉树为空,返回
2、不为空,先遍历左子树,然后遍历右子树,最后访问根节点
*/
void PostOrderTraverse(pTree T)
{
if(T == NULL)
return;
PostOrderTraverse(T->Left);
PostOrderTraverse(T->Right);
cout << T->value;
}
/*
前序遍历(非递归解法——栈模拟递归实现)
先访问,再入栈;
1、如果T非空,访问栈顶元素,把T入栈,T指向左儿子。。
2、如果T为空,说明已经向左走到尽头了,弹出当前栈顶元素,T指向右儿子。
*/
void PreOrderTraverse2(pTree T)
{
if(T == NULL)
return;
stack<pTree> Stk;
while(T || !Stk.empty())
{
if(T)
{
cout << T->value;
Stk.push(T);
T = T->Left;
}
else
{
T = Stk.top();
Stk.pop();
T = T->Right;
}
}
}
/*
中序遍历(非递归解法——栈模拟递归实现)
先入栈,后访问;
1、如果T非空,把T入栈,T指向左儿子。。
2、如果T为空,说明已经向左走到尽头了,弹出当前栈顶元素,进行访问,然后T指向右儿子。
*/
void InOrderTraverse2(pTree T)
{
if(T == NULL)
return;
stack<pTree> Stk;
while(T || !Stk.empty())
{
if(T)
{
Stk.push(T);
T = T->Left;
}
else
{
T = Stk.top();
Stk.pop();
cout << T->value;
T = T->Right;
}
}
}
/*
后序遍历(非递归解法)
采用两个栈来实现,不过就是先压入当前节点的左子树,后压入当前节点的右子树。
得到的顺序是根节点-右子树-左子树,刚好是后序遍历的逆序,所以再利用一个栈解决就可以倒过来。
*/
void PostOrderTraverse2(pTree T)
{
if(T == NULL)
return;
stack<pTree> Stk1,Stk2;
Stk1.push(T);
while(!Stk1.empty())
{
pTree p = Stk1.top();
Stk1.pop();
Stk2.push(p);
if(p->Left)
Stk1.push(p->Left);
if(p->Right)
Stk1.push(p->Right);
}
while(!Stk2.empty())
{
cout << Stk2.top()->value;
Stk2.pop();
}
}
/*
层序遍历(队列)
层序遍历就是从上到下从左到右访问树的节点。采用FIFO(先进先出)的数据结构-队列
先将根节点入队,当队列不为空时,弹出一个节点,然后访问,若左子树或右子树不为空,
将其入队
*/
void LevelTraverse(pTree T)
{
if(T == NULL)
return;
queue<pTree> que;
que.push(T);
while(!que.empty())
{
pTree p = que.front();
que.pop();
cout << p->value;
if(p->Left)
que.push(p->Left);
if(p->Right)
que.push(p->Right);
}
}
/*
二叉树第K层的结点个数
1、如果二叉树为空且k<1 则返回0;
2、如果二叉树不为空且k=1,返回1;
3、如果二叉树不为空且k>1,返回左子树中k-1层的结点个数与右子树中K-1层的结点个数之和
*/
int GetKthLevelNode(pTree T, int k)
{
if(T == NULL || k < 1)
return 0;
if(k == 1)
return 1;
int leftnum = GetKthLevelNode(T->Left, k - 1);
int rightnum = GetKthLevelNode(T->Right, k - 1);
return leftnum + rightnum;
}
int GetKthLevelNode2(pTree T, int k)
{
if(T == NULL || k < 0)
return 0;
int curLevel = 0;
int curLevelNode = 0;
queue<pTree> que;
que.push(T);
while(!que.empty())
{
curLevel ++;
curLevelNode = que.size(); // 当前层的结点个数
if(curLevel == k) // 如果当前层数等于所求的层数,跳出循环
break;
int cntNode = 0 ;
while(cntNode < curLevelNode) //如果当前层数还没到求的层数,将当前层结点弹出,下一层结点入栈
{
cntNode ++;
T = que.front();
que.pop();
if(T->Left != NULL)
que.push(T->Left);
if(T->Right != NULL)
que.push(T->Right);
}
}
while(!que.empty())
que.pop();
if(curLevel == k)
return curLevelNode;
return 0; //k 值大于树的深度,返回0
}
/*
求二叉树的叶结点个数(叶结点指没有左儿子和右儿子的结点)
*/
int GetTreeLeafsNum(pTree T)
{
if(T == NULL)
return 0;
if(T->Left == NULL && T->Right == NULL)
return 1;
int leftnum = GetTreeLeafsNum(T->Left);
int rightnum = GetTreeLeafsNum(T->Right);
return leftnum + rightnum;
}
bool FindPath(TreeNode* root, vector<ElementType>& path, ElementType ch)
{
if(root == NULL)
return false;
path.push_back(root->value);
if(ch == root->value)
return true;
bool found = false;
found = (FindPath(root->Left, path, ch) | FindPath(root->Right, path, ch));
if(!found)
path.pop_back();
return found;
}
ElementType FindLCA(TreeNode * root, ElementType ch1, ElementType ch2)
{
vector<ElementType> path1, path2;
ElementType ans;
bool find1 = FindPath(root, path1, ch1);
bool find2 = FindPath(root, path2, ch2);
if(find1 && find2)
{
for(int i = 0; i < path1.size(); i ++)
{
if(path1[i] != path2[i])
break;
else
ans = path1[i];
}
return ans;
}
return -1;
}
int main(int argc, char const *argv[])
{
/* code */
pTree Tnode = NULL;
CreatTree(&Tnode);
cout << "该二叉树节点个数为 " << GetTreeNum(Tnode) << endl;
cout << "该二叉树深度为 " << GetTreeDepth(Tnode) << endl;
cout << "前序遍历(递归)" << endl;
PreOrderTraverse(Tnode);
cout << endl;
cout << "前序遍历(非递归)" << endl;
PreOrderTraverse2(Tnode);
cout << endl;
cout << "中序遍历(递归)" << endl;
InOrderTraverse(Tnode);
cout << endl;
cout << "中序遍历(非递归)" << endl;
InOrderTraverse2(Tnode);
cout << endl;
cout << "后序遍历(递归)" << endl;
PostOrderTraverse(Tnode);
cout << endl;
cout << "后序遍历(非递归)" << endl;
PostOrderTraverse2(Tnode);
cout << endl;
cout << "层序遍历(队列)" << endl;
LevelTraverse(Tnode);
cout << endl;
cout << "二叉树第3层的结点个数为(递归): " << GetKthLevelNode(Tnode, 3) << endl;
cout << "二叉树第3层的结点个数为(非递归): " << GetKthLevelNode2(Tnode, 3) << endl;
cout << "二叉树叶结点个数为(递归): " << GetTreeLeafsNum(Tnode) << endl;
cout << "两个结点的最低公共祖先" << endl;
/*
A
B C
D E F G
H I J
K
*/
cout << "LCA(H,K)" << FindLCA(Tnode, 'H', 'K') << endl;
cout << "LCA(H,I)" << FindLCA(Tnode, 'H', 'I') << endl;
cout << "LCA(F,G)" << FindLCA(Tnode, 'F', 'G') << endl;
return 0;
}