以下便是所总结的关于树的各种算法, 算法将以函数的形式给出, 关于树的初始化等操作已经完成, 程序可以直接运行.关于树的算法题的精髓在于递归.
#include<bits/stdc++.h>
using namespace std;
// 定义二叉树结点的数据类型
typedef int ElemType;
typedef struct binode {
ElemType data;
struct binode *lchild, *rchild;
} BiNode, *BiTree;
// 算法1: 递归计算叶子结点数目的函数
int countLeafNodes(BiTree root) {
if (root == NULL) // 如果根节点为空,返回0
return 0;
else if (root->lchild == NULL && root->rchild == NULL){ // 如果是叶子节点,返回1
//cout<<root->data<<endl;
return 1+countLeafNodes(root->lchild) + countLeafNodes(root->rchild);
}
else // 递归计算左右子树的叶子节点数目,并相加
return countLeafNodes(root->lchild) + countLeafNodes(root->rchild);
//每一个分支节点最多只有两颗子树,从最后一层 countLeafNodes(root->lchild) + countLeafNodes(root->rchild)
//相加返回上一层的 countLeafNodes(root->lchild)
}
//算法2: 递归计算结点总数的函数
int countNodes(BiTree root) {
if (root == NULL)
return 0;
else return 1 + countNodes(root->lchild) + countNodes(root->rchild);
//每每递归到最后一层比如到节点4,此时root指向4节点, countNodes(root->lchild) + countNodes(root->rchild),
//分别进入这两个递归最后都return 0。
// 1 + countNodes(root->lchild) + countNodes(root->rchild);可以理解为,一个双亲的节点加上左右子树的节点
}
//算法3: 递归计算单分支结点总数
int countdfznode(BiTree root) {
if (root == NULL)
return 0;
if ((root->lchild == NULL && root->rchild != NULL) || (root->rchild == NULL && root->lchild != NULL))
return 1 + countdfznode(root->lchild) + countdfznode(root->rchild); //总体优化后的思路还是双亲加左加右
else
return countdfznode(root->lchild) + countdfznode(root->rchild);
}
//算法4: 计算最小结点
void minnode(BiTree root,int &min){
if(root==NULL)
return ;
if(root->data<min)
min=root->data;
minnode(root->lchild,min);//本质上是先序遍历
minnode(root->rchild,min);
return ;
}
//算法5: 计算k层上结点的个数
//层次遍历必须使用辅助队列
// 队列节点
typedef struct qnode {
BiTree data;
struct qnode *next;
} QNode;
// 队列结构
typedef struct {
QNode *front;
QNode *rear;
} LinkQueue;
// 初始化队列
void initQueue(LinkQueue &q) {
q.front = q.rear =(QNode*)malloc(sizeof(QNode));
q.front->next = NULL;
}
// 入队
void enQueue(LinkQueue &q, BiTree data){ //将树的一个结点看成队列的一个元素,见队列的存储结构的定义
QNode *newNode = new QNode;
newNode->data = data;
newNode->next = NULL;
q.rear->next = newNode;
q.rear = newNode;
}
// 出队
BiTree deQueue(LinkQueue &q) {
if (q.front == q.rear) {
return NULL;
}
QNode *p = q.front->next;
BiTree data = p->data;
q.front->next = p->next;
if (q.rear == p) {
q.rear = q.front;
}
delete p;
return data;
}
bool isEmpty(LinkQueue q) {
return q.front == q.rear;
}
//算法6: 层次遍历
void levelOrder(BiTree root) {
LinkQueue q;
initQueue(q);
enQueue(q, root);
while (!isEmpty(q)) {
BiNode *node =deQueue(q);
cout<<node->data<<" ";
if (node->lchild!=NULL) {
enQueue(q, node->lchild);
}
if (node->rchild!=NULL) {
enQueue(q, node->rchild);
}
}
}
//算法7: 第k层树有多少结点
int nodekcount(BiTree root,int k,int h) {//k是求第k层的节点
int num1=0,num2,num=0;
if(root!=NULL){
//h的初始值为1
if(h==k){
return 1+nodekcount(root->lchild,k,h+1)+nodekcount(root->rchild,k,h+1);
}
else
return nodekcount(root->lchild,k,h+1)+nodekcount(root->rchild,k,h+1);
//num1=levelkcount(root->lchild,k,h+1);
//num2=levelkcount(root->rchild,k,h+1);
//num+=num1+num2;//假设计算的是最后一层的结点数,上一层的2先执行r到4此时h==k,所以num=1、
//原理类似,会一直到最后一层然后将求和不断递归相加
//return num;
}
return 0;
}
int nodeklesf(BiTree root,int k){
return nodekcount(root,k,1);//从深度为1开始
}
//算法8: 第k层树有多少叶子结点
int levelkcount(BiTree root,int k,int h) {//k是求第k层的节点
if(root!=NULL){
//h的初始值为1
if(h==k){
if(root->lchild==NULL&&root->rchild==NULL)
return 1+levelkcount(root->lchild,k,h+1)+levelkcount(root->rchild,k,h+1);
}
else
return levelkcount(root->lchild,k,h+1)+levelkcount(root->rchild,k,h+1);
//num1=levelkcount(root->lchild,k,h+1);
//num2=levelkcount(root->rchild,k,h+1);
//num+=num1+num2;//假设计算的是最后一层的结点数,上一层的2先执行r到4此时h==k,所以num=1、
//原理类似,会一直到最后一层然后将求和不断递归相加
//return num;
}
return 0;
}
int levelklesf(BiTree root,int k){
return levelkcount(root,k,1);//从深度为1开始
}
//算法9: 求树的深度
void hightree(BiTree root,int &high,int h) {//
if(root==NULL)
return ;
if(h>high)
high=h;
if(root->lchild!=NULL)
hightree(root->lchild,high,h+1);
if(root->rchild!=NULL)
hightree(root->rchild,high,h+1);
return ;
}
//算法10: 判断x结点与y结点是否互为兄弟
bool isbrother(BiTree root, int x, int y) {
if (root == NULL) {
return false;
}
if (root->lchild != NULL && root->rchild != NULL) {
//如果仅仅用if(root->lchild->data==x&&root->rchild->data==y||root->lchild->data==y&&root->rchild->data==x)
//来判断到没到底,是不是对的,因为到底后,lchild本身就是空了,你还要访问人家的data,就会产生异常!!!
if ((root->lchild->data == x && root->rchild->data == y) || (root->lchild->data == y && root->rchild->data == x)) {
return true;
}
}
bool left = isbrother(root->lchild, x, y);
bool right = isbrother(root->rchild, x, y);
return left || right;
}
//算法11: 求结点x的子孙节点
void coutsun(BiTree root,int x) {
if(root==NULL)
return ;
if(root->data!=x)
cout<<root->data<<" ";
coutsun(root->lchild,x);
coutsun(root->rchild,x);
return ;
}
void findsun(BiTree root,int x) {
if(root==NULL)
return ;
if(root->data==x) {
coutsun(root,x);//为什么要单启用一个函数,因为还用现在的函数可能会一直遍历,不属于该子树的也遍历了
return ;
}
findsun(root->lchild,x);
findsun(root->rchild,x);
return ;
}
//算法12: 将二叉树的左右子树进行交换
BiTree swap(BiTree root) {
BiNode *t,*t1,*t2;
if(root==NULL) {
t=NULL;
}
else {
t=(BiNode*)malloc(sizeof(BiNode));
t->data=root->data;
t1=swap(root->lchild);
t2=swap(root->rchild);
t->lchild=t2;
t->rchild=t1;//一样是递归到最底端,每个子树从下往上进行交换
}
return t;
}
//算法13: 判断左右子树是否同构
bool symm(BiTree root1,BiTree root2) {
if(root1==NULL&&root2==NULL)
return true;
else if((root1==NULL&&root2!=NULL)||(root1!=NULL&&root2==NULL))
return false;
else
return symm(root1->lchild,root2->lchild)&symm(root1->rchild,root2->rchild);
}
bool symmtree(BiTree root) {
if(root==NULL)
return true;
else
return (root->lchild,root->rchild);
}
//算法14: 判断二叉树是否为完全二叉树
//借助层次遍历的思想
//1、没有左孩子就一定没有右孩子
//2、缺左孩子或者右孩子,则后继一定无孩子
bool perfecttree(BiTree root) {
LinkQueue q;
initQueue(q);
bool cm=true;//cm为真表示为完全二叉树
bool bj=true;//bj为真,表示目前所有结点均有左孩子还有右孩子
enQueue(q, root);
while (!isEmpty(q)) {
BiNode *node =deQueue(q);
if(node->lchild==NULL) {
bj=false;
if(node->rchild!=NULL){
cm=false;
return cm;
}
}
else {//有左孩子
if(!bj)//前面已经出现,要不缺右子树要不缺左右子树都没有的,后继还有孩子
cm=false;
enQueue(q, node->lchild);
if(node->rchild==NULL)
bj=false;
else
enQueue(q, node->rchild);
}
}
return cm;
}
//算法15: 将二叉链表转化为顺序存储
int sum=1;
void ctree(BiTree root,int a[],int i) {
if(root!=NULL) {
a[i]=root->data;
ctree(root->lchild,a,2*i);
ctree(root->rchild,a,2*i+1);
}
else
a[i]=-1;//如果该结点为空的话,执行完该次函数就要返回递归了
sum++;
}
// 定义链栈结点
typedef struct StackNode {
BiTree data;
struct StackNode* next;
} StackNode, * LinkStack;
// 初始化链栈
void initStack(LinkStack &S) {
S =(StackNode *)malloc(sizeof(StackNode));
S->next=NULL;
S->data=NULL;
}
//算法16: 判断链栈是否为空
bool isEmpty(LinkStack S) {
if(S->next==NULL)
return true;
else
return false;
}
// 入栈
void push(LinkStack &S, BiTree data) {
StackNode* newNode =(StackNode *)malloc(sizeof(StackNode));
newNode->data = data;
newNode->next = S->next;//带头指针的链表
S->next=newNode;
}
// 出栈
BiTree pop(LinkStack &S) {
if (isEmpty(S)) {
cout << "Stack Underflow" << endl;
return NULL;
} else {
BiTree data;
StackNode* temp = S->next;
S->next = temp->next;
data = temp->data;
delete temp;
return data;
}
}
//算法17: 非递归实现先序遍历
void preOrderTraversal(BiTree root) {
if (root == NULL) return;
LinkStack nodeStack;
initStack(nodeStack);
push(nodeStack, root);
while (!isEmpty(nodeStack)) {
BiTree node = pop(nodeStack);
cout << node->data << " ";
// 先将右子树压入栈中,保证左子树先于右子树访问
if (node->rchild != NULL) {
push(nodeStack, node->rchild);
}
// 再将左子树压入栈中
if (node->lchild != NULL) {
push(nodeStack, node->lchild);
}
}
}
//算法18: 后序遍历
void postOrderTraversal(BiTree root) {
if (root == NULL) return;
LinkStack stack1, stack2;
initStack(stack1);
initStack(stack2);
push(stack1, root);
while (!isEmpty(stack1)) {
BiTree node = pop(stack1);
push(stack2, node);
if (node->lchild != NULL) {
push(stack1, node->lchild);
}
if (node->rchild != NULL) {
push(stack1, node->rchild);
}
}
while (!isEmpty(stack2)) {
BiTree node = pop(stack2);
cout << node->data << " ";
}
}
//算法19: 先序序列第k个位置结点的值
int p=0;
void forworddatak(BiTree root,int k) {
if(root==NULL)
return ;
p++;
if(p==k) {
cout<<root->data;
return ;
}
forworddatak(root->lchild,k);
forworddatak(root->rchild,k);
return ;
}
//算法20: 中序遍历递归方法
void midorder(BiTree root) {
if(root==NULL)
return ;
midorder(root->lchild);
cout<<root->data<<" ";
midorder(root->rchild);
return ;
}//!!!!后序遍历亦是如此,只要更改操作的位置就可以,是在两个递归的中间还是上面还是下面
//算法21: 查找最近公共祖先
BiTree lowestCommonAncestor(BiTree root, BiTree p, BiTree q) {
if (root == NULL || root == p || root == q) return root;
BiTree left = lowestCommonAncestor(root->lchild, p, q);
BiTree right = lowestCommonAncestor(root->rchild, p, q);
//典型的后序遍历,将操作的位置放在两个递归的下面
if (left != NULL && right != NULL) return root;
if (left != NULL) return left;
if (right != NULL) return right;
return NULL;
}
// 初始化二叉树
void initBitree(BiTree &root) {
root = (BiTree)malloc(sizeof(BiNode));
root->data = 1;
root->lchild = (BiTree)malloc(sizeof(BiNode));
root->lchild->data = 2;
root->lchild->lchild = (BiTree)malloc(sizeof(BiNode));
root->lchild->lchild->data = 4;
root->lchild->lchild->lchild = NULL;
root->lchild->lchild->rchild = NULL;
root->lchild->rchild = (BiTree)malloc(sizeof(BiNode));
root->lchild->rchild->data = 5;
root->rchild = (BiTree)malloc(sizeof(BiNode));
root->rchild->data = 3;
root->rchild->lchild = (BiTree)malloc(sizeof(BiNode));
root->rchild->rchild = (BiTree)malloc(sizeof(BiNode));
root->rchild->lchild->data = 6;
root->rchild->rchild->data = 7;
root->rchild->lchild->lchild = NULL;
root->rchild->lchild->rchild = NULL;
root->rchild->rchild->lchild = NULL;
root->rchild->rchild->rchild = NULL;
}
//孩子兄弟表示法,不一定是二叉树,度为3,为4都有可能
typedef struct CSNode{
ElemType data;
struct CSNode *firstchild ,*nextsibling;//该节点的第一个孩子与该节点的下一个兄弟
}CSNode,*CSTree;
//双亲表示法
#define MAX_TREE_SIZE 100
typedef struct {
ElemType data;
int parent;
}PTNode;
typedef struct {
PTNode nodes[MAX_TREE_SIZE];
int n;
}PTree;
// 初始化孩子兄弟表示法的树
void initCSTree(CSTree &root_1, ElemType data) {
root_1 = new CSNode;
root_1->data = data;
root_1->firstchild = NULL;
root_1->nextsibling = NULL;
}
// 创建示例的树
void createExampleTree(CSTree &root_1) {
CSTree a, b, c, d, e, f;
initCSTree(a, 'a');
initCSTree(b, 'b');
initCSTree(c, 'c');
initCSTree(d, 'd');
initCSTree(e, 'e');
initCSTree(f, 'f');
a->firstchild = b;
b->nextsibling = c;
b->firstchild = d;
d->nextsibling = e;
e->nextsibling = f;
root_1 = a;
}
//算法22: 孩子兄弟表示法统计叶子数量
int countLeaves(CSTree root_1) {
if (root_1 == NULL) return 0;
if (root_1->firstchild == NULL) return 1;
int count = 0;
CSTree p = root_1->firstchild;//依据为如果该节点的第一个左孩子域为空,那么就为叶子结点
while (p != NULL) {
count += countLeaves(p);
p = p->nextsibling;
}
return count;
}
//算法23: 孩子兄弟表示法计算树的度
int maxDegree(CSTree root) {
if (root == NULL) return 0;
int maxChildDegree = 0;
int currentChildDegree = 0;//当前节点的度
CSTree p = root->firstchild;
while (p != NULL) {
currentChildDegree++;
int tempDegree = maxDegree(p);
maxChildDegree = max(maxChildDegree, tempDegree);
p = p->nextsibling;
}
return max(maxChildDegree, currentChildDegree);
}
//算法24: 孩子兄弟表示法计算树的深度
int depth(CSTree root) {
if (root == NULL) return 0;
int maxChildDepth = 0;
CSTree p = root->firstchild;
while (p != NULL) {
int currentChildDepth = depth(p);//currentChildDepth只有进入到下一层才会+
maxChildDepth = max(maxChildDepth, currentChildDepth);
p = p->nextsibling;
}
return maxChildDepth + 1;
}
// 初始化双亲表示法树
void initPTree(PTree &tree) {
tree.n = 0;
}
// 插入双亲表示法树节点
void insertPTreeNode(PTree &tree, ElemType data, int parent) {
tree.nodes[tree.n].data = data;
tree.nodes[tree.n].parent = parent;
tree.n++;
}
// 创建示例的双亲表示法树
void createExamplePTree(PTree &tree) {
initPTree(tree);
insertPTreeNode(tree, 'a', -1);
insertPTreeNode(tree, 'b', 0);
insertPTreeNode(tree, 'c', 0);
insertPTreeNode(tree, 'd', 1);
insertPTreeNode(tree, 'e', 1);
insertPTreeNode(tree, 'f', 1);
}
//双亲表示法计算树的深度
int depthPTree(PTree tree, int index) {
int maxDepth = 0;
for (int i = 0; i < tree.n; i++) {
if (tree.nodes[i].parent == index) {
int currentDepth = depthPTree(tree, i);
maxDepth = max(maxDepth, currentDepth);
}
}
return maxDepth + 1;
}
// 测试示例
int main() {
BiTree root;
initBitree(root);
cout<<"********关于二叉树的各种算法结果如下********"<<endl;
cout<<"叶子结点总数为: "<<countLeafNodes(root)<<endl;
cout<<"节点总数为: "<<countNodes(root)<<endl;
cout<<"单分支节点总数为: "<<countdfznode(root)<<endl;
int min=root->data;minnode(root,min);cout<<"最小节点为: "<<min<<endl;
cout<<"第2层结点总数为:"<<nodeklesf(root,2)<<endl;
cout<<"第3层结点包含的叶子结点总数为:"<<levelklesf(root,3)<<endl;
cout<<"层次遍历结果为:";levelOrder(root);cout <<endl;
int high=0;hightree(root,high,1);cout<<"树的深度为:"<<high<<endl;
cout<<"6与7是兄弟节点的判断为:"<<isbrother(root,6,7)<<endl;
cout<<"结点3的子孙节点为:";findsun(root,3);cout<<endl;
cout<<"二叉树进行左右子树交换后的层次遍历结果为:";BiTree root1=swap(root);levelOrder(root1);cout<<endl;
cout<<"二叉树左右子树是否同构的判断为:"<<symmtree(root)<<endl;
cout<<"二叉树是否为完全二叉树的判断为:"<<perfecttree(root)<<endl;
int a[100];cout<<"转化为顺序存储后为:";ctree(root,a,1);for(int j=1;j<sum;j++) cout<<a[j]<<" ";cout<<endl;
cout<<"使用栈对二叉树非递归先序遍历结果为:";preOrderTraversal(root);cout<<endl;
cout<<"使用栈对二叉树非递归后序遍历结果为:";postOrderTraversal(root);cout<<endl;
cout<<"先序序列第4个位置的结点的值为:";forworddatak(root,4);cout<<endl;
cout<<"递归中序遍历结果为:";midorder(root);cout<<endl;
cout<<"查找4和6的最近公共祖先为:";BiNode *ancestor=lowestCommonAncestor(root, root->lchild->lchild, root->rchild->lchild);cout<<ancestor->data<<endl;
CSTree root_1;
createExampleTree(root_1);
cout<<"孩子-兄弟表示法统计叶子结点总数为:"<<countLeaves(root_1)<<endl;
cout<<"孩子兄弟表示法计算树的度为:"<<maxDegree(root_1)<<endl;
cout<<"孩子兄弟表示法计算树的深度为:"<<depth(root_1)<<endl;
PTree tree;
createExamplePTree(tree);
cout<<"双亲表示法计算树的深度为:"<<depthPTree(tree,0)<<endl;
return 0;
}
运行结果如下所示, 以便于对照学习.
*********关于二叉树的各种算法结果如下********
叶子结点总数为: 4
节点总数为: 7
单分支节点总数为: 0
最小节点为: 1
第2层结点总数为:2
第3层结点包含的叶子结点总数为:4
层次遍历结果为:1 2 3 4 5 6 7
树的深度为:3
6与7是兄弟节点的判断为:1
结点3的子孙节点为:6 7
二叉树进行左右子树交换后的层次遍历结果为:1 3 2 7 6 5 4
二叉树左右子树是否同构的判断为:1
二叉树是否为完全二叉树的判断为:1
转化为顺序存储后为:1 2 3 4 5 6 7 -1 -1 -1 -1 -1 -1 -1 -1
使用栈对二叉树非递归先序遍历结果为:1 2 4 5 3 6 7
使用栈对二叉树非递归后序遍历结果为:4 5 2 6 7 3 1
先序序列第4个位置的结点的值为:5
递归中序遍历结果为:4 2 5 1 6 3 7
查找4和6的最近公共祖先为:1
孩子-兄弟表示法统计叶子结点总数为:4
孩子兄弟表示法计算树的度为:3
孩子兄弟表示法计算树的深度为:3
双亲表示法计算树的深度为:3