1.根据前序序列和中序序列创建二叉树
2.求二叉树中节点的个数
3.求二叉树中叶子节点的个数
4.求二叉树的高度
5.求二叉树的宽度
6.求二叉树第K层的节点个数
7.判断二叉树是否是完全二叉树
8.求二叉树中节点的最大距离
9.求二叉树中两个节点的最近公共祖先节点
10.输出一个二叉树的前序序列
11.输出一个二叉树的中序序列
12.输出一个二叉树的后序序列
13.输出一个二叉树的层次序列
14.左右子树互换
15.判断两棵树是否是相同
16.判断第二棵树是否是第一棵树的子树
17.合并两棵二叉树
18.复制一棵二叉树
操作1是创建二叉树是后面操作的基础,输入是2个string类型的字符串
二叉树tree是有限个元素的集合(可以为空),当二叉树非空时,其中一个元素为根,余下的元素(如果有的话)被划分为两棵二叉树,分别为tree的左子树和右子树
因为二叉树的定义就是一种递归的定义,因此很多操作都可以用递归的方法来实现
所有操作都已经验证
下面是操作中会用到的数据结构
// 树的节点
struct treeNode
{
char element;
treeNode *leftChild;
treeNode *rightChild;
treeNode()
{
leftChild = rightChild = NULL;
}
treeNode(char theElement)
{
element = theElement;
leftChild = rightChild = NULL;
}
treeNode(char theElement, treeNode *theLeftChild, treeNode *theRightChild)
{
element = theElement;
leftChild = theLeftChild;
rightChild = theRightChild;
}
};
// 队列的数据结构
class arrayQueue
{
public:
treeNode* queue[100];
arrayQueue()
{
queueFront = -1;
elementSize = 0;
queueBack = -1;
}
void push(treeNode *theTreeNode)
{
queueBack = (queueBack+1)%100;
queue[queueBack] = theTreeNode;
elementSize++;
}
void pop()
{
queueFront = (queueFront+1)%100;
delete queue[queueFront];
elementSize--;
}
treeNode* front()
{
return queue[(queueFront+1)%100];
}
bool empty()
{
return elementSize == 0;
}
private:
int queueFront; // 队首元素的前一个索引
int elementSize;
int queueBack; // 队尾元素的索引
};
1.根据前序序列和中序序列创建二叉树
思想:递归求解,前序序列的第一个节点是根节点,在中序序列中找到该根节点,其左半部分为左子树,右半部分为右子树,对左子树和右子树继续执行该过程
treeNode* makeTree(string str1, string str2, int degree)
{
// str1为前序序列 str2为中序序列 degree为二叉树的度
if (degree == 0)
return NULL;
int k = 0;
while (str1[0] != str2[k])
k++;
treeNode *tree = new treeNode(str1[0]);
tree->leftChild = makeTree(str1.substr(1, k), str2.substr(0, k), k);
tree->rightChild = makeTree(str1.substr(k+1, degree-k-1), str2.substr(k+1, degree-k-1), degree-k-1);
return tree;
}
2.求二叉树中节点的个数
思想:递归求解,二叉树的节点个数=左子树的节点数+右子树的节点数+根节点
int getNums(treeNode* tree)
{
if (tree == NULL)
return 0;
return getNums(tree->leftChild) + getNums(tree->rightChild) + 1;
}
3.求二叉树中叶子节点的个数
思想:递归求解,叶子节点是自身非空,左右子节点都为空。计算左右子节点都为空的节点数目。
int getLeafNums(treeNode* tree)
{
if (tree == NULL)
return 0;
if (tree->leftChild == NULL && tree->rightChild == NULL)
return 1;
int leftNums = getLeafNums(tree->leftChild);
int rightNums = getLeafNums(tree->rightChild);
return leftNums + rightNums;
}
4.求二叉树的高度
思想:递归求解,二叉树的高度=max(左子树的高度, 右子树的高度) + 1
int getHeight(treeNode* tree)
{
if (tree == NULL)
return 0;
int maxLeft = getHeight(tree->leftChild);
int maxRight = getHeight(tree->rightChild);
return maxLeft > maxRight ? (maxLeft+1) : (maxRight+1);
}
5.求二叉树的宽度
思想:树的宽度是指,元素最多的那一层的元素数量
递归求解,计算每一层的宽度,求所有宽度中的最大值
void getWidth(treeNode* tree, int result[], int p)
{
// result数组初始化为0,p为当前的层数初始时传入1
// 在main函数中,result数组中的最大值即为二叉树的宽度,或者在该方法末尾加一
// 个if(p==1) {求数组最大值}
if (tree != NULL)
{
result[p] += 1;
getWidth(tree->leftChild, result, p+1);
getWidth(tree->rightChild, result, p+1);
}
}
6.求二叉树第k层的节点个数
思想:递归求解,二叉树第k层节点的个数=第k-1层左子树的数目+第k-1层右子树的数目
int getLevelNums(treeNode* tree, int k)
{
if (tree == NULL || k == 0)
return 0;
if (k == 1)
return 1;
int leftNums = getLevelNums(tree->leftChild, k-1);
int rightNums = getLevelNums(tree->rightChild, k-1);
return leftNums + rightNums;
}
7.判断二叉树是否是完全二叉树
思想:完全二叉树中只有最后一层的右侧才可以有空节点
层序遍历,一旦一个节点含有空子树,之后所有节点的子树都为空才是完全二叉树
bool isCompleteBinaryTree(treeNode* tree)
{
if (tree == NULL)
return true;
arrayQueue q;
bool haveNULL = false;
treeNode* root = tree;
q.push(root);
while (!q.empty())
{
root = q.front();
q.pop();
if (haveNULL)
{
if (root->leftChild != NULL || root->rightChild != NULL)
return false;
}
else
{
if (root->leftChild != NULL && root->rightChild != NULL)
{
// 左右非空
q.push(root->leftChild);
q.push(root->rightChild);
}
else if (root->leftChild != NULL && root->rightChild == NULL)
{
// 左非空右空
haveNULL = true;
q.push(root->leftChild);
}
else if (root->leftChild == NULL && root->rightChild != NULL)
{
// 左空右非空
return false;
}
else
{
// 左右为空
haveNULL = true;
}
}
}
return true;
}
8.求二叉树中节点的最大距离
思想:该距离是指任意两个节点相连的路径长度的最大值,一定要理解好这个概念
树为空:距离为0;
树非空:左子树中的最大距离,右子树中的最大距离,从左子树到根再到右子树的最大距离;
这两个节点可能分别在根节点的左右子树上,也可能在根节点的同一棵子树上。
int getMaxDistance(treeNode* tree, int& maxLeft, int& maxRight)
{
// maxLeft和maxRight分别为左右子树中的节点到根的最大距离
// 初始时传入maxLeft = maxRight = 0
if (tree == NULL)
{
maxLeft = 0;
maxRight = 0;
return 0;
}
// 下面四个变量表示当前节点的左右子树中,到该节点左右子节点的最大距离
int maxLL = 0, maxLR = 0, maxRL = 0, maxRR = 0;
int maxDistLeft = 0, maxDistRight = 0; // 左、右子树中的最大距离
if (tree->leftChild) {
maxDistLeft = getMaxDistance(tree->leftChild, maxLL, maxLR);
maxLeft = max(maxLL, maxLR) + 1;
} else {
maxDistLeft = 0;
maxLeft = 0;
}
if (tree->rightChild) {
maxDistRight = getMaxDistance(tree->rightChild, maxRL, maxRR);
maxRight = max(maxRL, maxRR) + 1;
} else {
maxDistRight = 0;
maxRight = 0;
}
return max(maxLeft+maxRight, max(maxDistLeft, maxDistRight));
}
9.求二叉树中两个节点的最近公共祖先节点
思想:递归求解,如果两个节点分别在根节点的左子树和右子树中,那么最近公共祖先节点是根节点。如果两个都在左子树或都在右子树,则递归处理左子树或递归处理右子树。
需要一个辅助函数在该函数的下方,需要的关于STL中list的知识,会在注释中给出,现在你需要知道list将元素有序存储在链表中
默认根节点的祖先节点为根节点
treeNode* getLastCommon(treeNode* tree, treeNode* node1, treeNode* node2)
{
if (tree == NULL || node1 == NULL || node2 == NULL)
return NULL;
list<treeNode*> path1, path2;
bool found1 = getPath(tree, node1, path1);
bool found2 = getPath(tree, node2, path2);
treeNode* ancester = NULL; // 英文小贴士:ancester 祖先
if (!found1 || !found2)
return NULL;
list<treeNode*>::const_iterator iter1 = path1.begin(); // 该函数:返回指向第一个元素的迭代器。
list<treeNode*>::const_iterator iter2 = path2.begin();
while (iter1 != path1.end() && iter2 != path2.end()) // 该函数:返回末尾的迭代器
{
if (*iter1 != *iter2)
break;
ancester = *iter1;
iter1++;
iter2++;
}
return ancester;
}
// 下面是辅助函数
bool getPath(treeNode* root, treeNode* node, list<treeNode*> &path)
{
if (root == NULL)
return false;
// 获得根到该节点的路径
if (root->element == node->element)
{
path.push_back(root); // 该函数:在list的末尾添加一个元素。
return true;
}
bool found = false;
path.push_back(root); // 路径从根节点开始
found = getPath(root->leftChild, node, path); // 在左子树中查找
if (!found)
found = getPath(root->rightChild, node, path); // 在右子树中查找
if (!found)
path.pop_back(); // 该函数:删除最后一个元素。在此树中没找到,pop出已压入的此子树的节点
return found;
}
10.输出一个二叉树的前序序列
void preOrder(treeNode *tree)
{
if (tree != NULL)
{
cout << tree->element;
preOrder(tree->leftChild);
preOrder(tree->rightChild);
}
}
11.输出一个二叉树的中序序列
void inOrder(treeNode *tree)
{
if (tree != NULL)
{
inOrder(tree->leftChild);
cout << tree->element;
inOrder(tree->rightChild);
}
}
12.输出一个二叉树的后序序列
void postOrder(treeNode *tree)
{
if (tree != NULL)
{
postOrder(tree->leftChild);
postOrder(tree->rightChild);
cout << tree->element;
}
}
13.输出一个二叉树的层次序列
void levelOrder(treeNode *tree)
{
arrayQueue q;
q.push(tree);
while (!q.empty())
{
tree = q.top();
cout << tree->element;
if (tree->leftChild != NULL)
q.push(tree->leftChild);
if (tree->rightChild != NULL)
q.push(tree->rightChild);
q.pop();
}
}
14.左右子树互换
思想:递归求解,递归的交换左右子树
treeNode* transformTree(treeNode* tree)
{
if (tree == NULL)
return NULL;
treeNode* left = transformTree(tree->leftChild);
treeNode* right = transformTree(tree->rightChild);
tree->leftChild = right;
tree->rightChild = left;
return tree;
}
15.判断两棵树是否是相同
思想:递归求解,先判断根是否相同,再判断左子树和右子树是否相同
bool judgeTreeEqual(treeNode* tree1, treeNode* tree2)
{
if (tree1 == NULL && tree2 == NULL)
return true;
if (tree1 == NULL || tree2 == NULL)
return false;
if (tree1->element != tree2->element)
return false;
bool left = judgeTreeEqual(tree1->leftChild, tree2->leftChild);
bool right = judgeTreeEqual(tree1->rightChild, tree2->rightChild);
return left && right;
}
16.判断第二棵树是否是第一棵树的子树
思想:空树不是任何一棵树的子树,判断tree1是否含有tree2
递归求解,判断以当前根为节点的树是否包含,否则去左子树中寻找,再否则去右子树中寻找
需要一个辅助函数在该函数的下方
bool judgeTreeHasSubtree(treeNode* tree1, treeNode* tree2)
{
bool result = false;
if (tree1 != NULL && tree2 != NULL)
{
if (tree1->element == tree2->element)
{
result = isHasSubtree(tree1, tree2);
}
if (!result)
{
result = judgeTreeHasSubtree(tree1->leftChild, tree2);
}
if (!result)
{
result = judgeTreeHasSubtree(tree1->rightChild, tree2);
}
}
return result;
}
// 辅助函数
bool isHasSubtree(treeNode* tree1, treeNode* tree2)
{
// tree2遍历完了且都对应上,返回true
if (tree2 == NULL)
{
return true;
}
// tree1遍历完了但tree2没有遍历完,返回false
if (tree1 == NULL)
{
return false;
}
if (tree1->element != tree2->element)
{
return false;
}
return isHasSubtree(tree1->leftChild, tree2->leftChild) && isHasSubtree(tree1->rightChild, tree2->rightChild);
}
17.合并两棵二叉树
思想:合并规则:如果两个节点重叠,则以新节点的值为准。tree1为旧树,tree2为新树。将tree2合并到tree1中。
你也可以制定你自己的合并规则,可以相加相减等等
void mergeTwoTrees(treeNode* tree1, treeNode* tree2)
{
if (tree1 != NULL && tree2 != NULL)
{
tree1->element = tree2->element;
mergeTwoTrees(tree1->leftChild, tree2->leftChild);
mergeTwoTrees(tree1->rightChild, tree2->rightChild);
}
if (tree1 == NULL && tree2 != NULL)
{
tree1 = tree2;
}
}
18.复制一棵二叉树
思想:递归复制,先复制根节点,再复制左子树和右子树
treeNode* copyTree(treeNode* tree)
{
if (tree == NULL)
return NULL;
treeNode* newTree = new treeNode(tree->element);
newTree->leftChild = copyTree(tree->leftChild);
newTree->rightChild = copyTree(tree->rightChild);
return newTree;
}