//****算法复习*********
//****使用纯C编写****************
//******作者:王强******
//最后一次修改日期:2020年7月18日(持续更新)
#include<iostream>
using namespace std;
#define maxSize 50
typedef int ElemType;
typedef enum { Link, Thread }PointerTag; //Link = 0表示指向左右孩子指针;Thread = 1表示指向前驱或后继的线索
//*************************************************************************************************************
typedef struct BiNode //二叉树存储结构
{
ElemType data; //数据域
struct BiNode* lchild; //左孩子
struct BiNode* rchild; //右孩子
}BiNode;
typedef struct ThreadBiNode //线索二叉树存储结构
{
ElemType data;
struct ThreadBiNode* lchild;
struct ThreadBiNode* rchild;
int ltag; //左线索标志
int rtag; //右线索标志
}ThreadBiNode;
//*************************************************************************************************************
BiNode* Createtree(ElemType a[], int n1, int m1, ElemType b[], int n2, int m2);//根据先序和中序遍历结果创建唯一确定的二叉树
ThreadBiNode* CreateTree(ElemType a[], int n1, int m1, ElemType b[], int n2, int m2);//根据先序和中序遍历结果创建唯一确定的二叉树
void pre_Noncirculate(BiNode* T); //先序遍历二叉树的非递归算法
void Inorder_Noncirculate(BiNode* T); //中序遍历二叉树的非递归算法
void Post_Noncirculate(BiNode* T);//后序遍历二叉树的非递归算法
void LevelOrder(BiNode* T);//二叉树层次遍历
void LevelOrder2(ThreadBiNode* T);//线索二叉树层次遍历
int Tree_High(BiNode* T); //求二叉树高度的非递归算法
int Tree_High2(BiNode* T); //求二叉树高的递归算法
void Tree_levelSum(BiNode* T); //求二叉树每层的结点个数
int CountDoublesonNodes(BiNode* T); //统计一棵二叉树中双分支结点的个数
BiNode* SwapTree(BiNode* T); //交换左右子树
void Find_Pre(BiNode* T, int k); //找先序遍历序列中第k个结点的值
void DeleteTree(BiNode* T); //删除一棵以T为根的二叉树
void FindThenDelete(BiNode* T, ElemType x); //在二叉树中查找所有结点值为x的结点,并删除以其为根的子树
int FindAncestorToChild(BiNode* T, ElemType X, BiNode* temp[]);//求根节点到某一结点的路径,temp为辅助栈,用来存放祖先结点,返回辅助栈的栈顶指针
void FindCommonAncestor(BiNode* T, ElemType x, ElemType y, BiNode* temp1[], BiNode* temp2[]);//查找两个结点的公共祖先
void InThread(ThreadBiNode* &T,ThreadBiNode *&pre);//对二叉树进行中序线索化
void CreateInThread(ThreadBiNode* T);//建立中序线索二叉树
ThreadBiNode* FirstNode(ThreadBiNode* T);//在中序线索二叉树中,查找中序序列下的第一个结点
ThreadBiNode* NextNode(ThreadBiNode* T);//在中序线索二叉树中,查找结点的中序后继结点
void ThreadInOrder(ThreadBiNode* T); //在中序线索二叉树上使用线索执行二叉树中序遍历
ThreadBiNode* InPostPre(ThreadBiNode* T, ThreadBiNode* p);//在中序线索树上求指定结点在后序前驱结点
//*************************************************************************************************************
int main()
{
ElemType pre[] = { 9,7,3,51,8,16,22,0,2,4 }, in[] = { 3,8,51,16,7,9,0,22,4,2 };//先序序列和中序序列
ThreadBiNode* T = CreateTree(pre, 0, 9, in, 0, 9);
//BiNode* temp1[maxSize], * temp2[maxSize];
//Inorder_Noncirculate(T);
//Post_Noncirculate(T);
/*BiNode* stacka[maxSize]; //定义辅助栈stacka并初始化
int topa=FindAncestorToChild(T, 8,stacka);
while (topa!=-1) //访问辅助栈中的结点
{
printf("%d%s", stacka[topa--]->data," ");
}*/
//FindCommonAncestor(T, 51, 22, temp1, temp2);
//printf("%d\n", T->rchild->lchild->ltag);
//LevelOrder2(T);
CreateInThread(T);
//printf("%d\n", T->rchild->lchild->ltag);
//T = T->rchild->rchild->lchild->lchild;
//printf("%d\n", T->rchild->lchild->lchild->ltag);
//printf("%d\n",FirstNode(T)->data);
//ThreadInOrder(T);
ThreadBiNode* temp = T->rchild;
//InPostPre(T, temp);
//printf("%d\n", T->rtag);
printf("%d\n", InPostPre(T, temp)->data);
//printf("%s%d", "树高:",Tree_High2(T));
//Tree_levelSum(T);
//pre_Noncirculate(T);
//printf("%d%s", CountDoublesonNodes(T)," ");
//LevelOrder(SwapTree (T));
//Find_Pre(T,5);
//T=DeleteTree(T);
//FindThenDelete(T, 9);
printf("\n");
//pre_Noncirculate(T);
//LevelOrder(T);
//T = NULL;
//printf("\n%p\n", T);
//if (T!= NULL)
//cout << "1w21";
system("pause");
return 0;
}
//*************************************************************************************************************
BiNode* Createtree(ElemType a[], int n1, int m1, ElemType b[], int n2, int m2)//根据先序和中序遍历结果创建唯一确定的二叉树
{
BiNode* root = (BiNode*)malloc(sizeof(BiNode));
root->data = a[n1];
int i=0, llen=0, rlen=0;
for (; b[i] != root->data ; i++);//找到根节点在中序序列的下标i;
llen = i - n2;//左子树长
rlen = m2 - i;//右子树长
if (llen!=0) //当左子树长不为零时建左子树
root->lchild = Createtree(a, n1 + 1, n1 + llen, b, n2, n2 + llen - 1);//新的建树序列(新的中序序列)对应b的起始下标n2,
else //结束下标n2+len-1;新的参考序列(新的先序序列)对应a的起始坐标n1+1,结束坐标n1+len;
root->lchild = NULL;
if (rlen != 0)//当右子树长不为零时建右子树
root->rchild = Createtree(a, m1 - rlen + 1, m1, b, m2 - rlen + 1, m2);//新的建树序列(新的中序序列)对应b的起始下标m2-rlrn+1,
else //结束下标m2;新的参考序(新的先序序列)列对应a的起始坐标m1-rlen+1,结束坐标m1;
root->rchild = NULL;
return root;
}
//*************************************************************************************************************
ThreadBiNode* CreateTree(ElemType a[], int n1, int m1, ElemType b[], int n2, int m2)//根据先序和中序遍历结果创建唯一确定的二叉树
{
ThreadBiNode* root = (ThreadBiNode*)malloc(sizeof(ThreadBiNode));
root->data = a[n1];
root->ltag = root->rtag = 0;
int i = 0, llen = 0, rlen = 0;
for (; b[i] != root->data; i++);//找到根节点在中序序列的下标i;
llen = i - n2;//左子树长
rlen = m2 - i;//右子树长
if (llen != 0) //当左子树长不为零时建左子树
{
root->lchild = CreateTree(a, n1 + 1, n1 + llen, b, n2, n2 + llen - 1);//新的建树序列(新的中序序列)对应b的起始下标n2,
root->ltag = root->rtag = 0;
}
else //结束下标n2+len-1;新的参考序列(新的先序序列)对应a的起始坐标n1+1,结束坐标n1+len;
{
root->lchild = NULL;
root->ltag = root->rtag = 0;
}
if (rlen != 0)//当右子树长不为零时建右子树
{
root->rchild = CreateTree(a, m1 - rlen + 1, m1, b, m2 - rlen + 1, m2);//新的建树序列(新的中序序列)对应b的起始下标m2-rlrn+1,
root->ltag = root->rtag = 0;
}
else //结束下标m2;新的参考序(新的先序序列)列对应a的起始坐标m1-rlen+1,结束坐标m1;
{
root->rchild = NULL;
root->ltag = root->rtag = 0;
}
return root;
}
//*************************************************************************************************************
void pre_Noncirculate(BiNode* T) //先序遍历二叉树的非递归算法
{
if (T == NULL)
return;
BiNode* stack[maxSize],*p=T; int top = -1;
stack[++top] = p;
while (top != -1)
{
p = stack[top--];
printf("%d%s", p->data, " ");
if (p->rchild != NULL)
stack[++top] = p->rchild;
if (p->lchild != NULL)
stack[++top] = p->lchild;
}
}
//*************************************************************************************************************
void Inorder_Noncirculate(BiNode* T) //中序遍历二叉树的非递归算法
{
if(T==NULL)//如果树是空树,退出
return;
BiNode* stack[maxSize]; int top = -1;
BiNode* p = T;//工作指针
while (top != -1 || p != NULL)
{
if (p != NULL)
{
stack[++top] = p;
p = p->lchild;
}
else
{
p = stack[top--];
printf("%d", p->data);
p = p->rchild;
}
}
}
//*************************************************************************************************************
void Post_Noncirculate(BiNode* T)//后序遍历二叉树的非递归算法
{
if (T == NULL)
return;
BiNode* stack[maxSize], * p = T,*r=NULL; int top = -1;//p是工作指针,r是辅助指针,指向最近访问过的结点
while (p != NULL || top != -1)
{
if (p != NULL) // 找到最左的结点
{
stack[++top] = p;
p = p->lchild;
}
else
{
p = stack[top];//取栈顶结点
if (p->rchild!=NULL && p->rchild != r)//若右子树存在,且未被访问过
{
p = p->rchild; //转向右子树
stack[++top] = p; //压入栈
p = p->lchild; //依旧往左走
}
else //否则,弹栈并访问
{
p=stack[top--]; //弹出结点
printf("%d%s", p->data," ");//访问结点
r = p; //记录最近访问过的结点
p = NULL; //结点访问完后,重置p指针
}
}
}
}
//*************************************************************************************************************
int FindAncestorToChild(BiNode* T, ElemType X,BiNode *temp[])//求根节点到某一结点的路径,temp为辅助栈,用来存放祖先结点,返回辅助栈的栈顶指针
{
if (T == NULL)
exit(0);
BiNode* stack[maxSize], * p = T, * r = NULL; //p是工作指针,r是辅助指针,指向最近访问过的结点
int top = -1,topa=-1;//栈初始化
while (p != NULL || top != -1)
{
if (p != NULL) // 找到最左的结点
{
stack[++top] = p;
p = p->lchild;
}
else
{
p = stack[top];//取栈顶结点
if (p->rchild != NULL && p->rchild != r)//若右子树存在,且未被访问过
{
p = p->rchild; //转向右子树
stack[++top] = p; //压入栈
p = p->lchild; //依旧往左走
}
else //否则,弹栈并访问
{
p = stack[top--]; //弹出结点
if(p->data==X) //访问到值为X的结点时,栈中结点是其所有祖先
{
while (top != -1)
{
temp[++topa] = p; //将祖先结点压入辅助栈中
p = stack[top--];
}
temp[++topa] = p; //根节点入辅助栈
}
r = p; //记录最近访问过的结点
p = NULL; //结点访问完后,重置p指针
}
}
}
return topa;
}
//*************************************************************************************************************
void LevelOrder(BiNode* T)//二叉树层次遍历
{
if (T == NULL)
return ;
BiNode* queue[maxSize],*p;//定义一个循环队列,还有一个工作指针p
int front = 0, rear = 0; //初始化循环队列
queue[rear] = T;
rear = (rear + 1) % maxSize;//根结点入队
while (front != rear) //队列不空时循环
{
p = queue[front];
front = (front + 1) % maxSize;//队头元素出队
printf("%d%s", p->data, " "); //访问出队元素
if (p->lchild != NULL) //左子树不空则进队
{
queue[rear] = p->lchild;
rear = (rear + 1) % maxSize;
}
if (p->rchild!= NULL)//右子树不空则进队
{
queue[rear] = p->rchild;
rear = (rear + 1) % maxSize;
}
}
}
//*************************************************************************************************************
void LevelOrder2(ThreadBiNode* T)//二叉树层次遍历
{
if (T == NULL)
return;
ThreadBiNode* queue[maxSize], * p;//定义一个循环队列,还有一个工作指针p
int front = 0, rear = 0; //初始化循环队列
queue[rear] = T;
rear = (rear + 1) % maxSize;//根结点入队
while (front != rear) //队列不空时循环
{
p = queue[front];
front = (front + 1) % maxSize;//队头元素出队
printf("%d%s", p->data, " "); //访问出队元素
if (p->lchild != NULL) //左子树不空则进队
{
queue[rear] = p->lchild;
rear = (rear + 1) % maxSize;
}
if (p->rchild != NULL)//右子树不空则进队
{
queue[rear] = p->rchild;
rear = (rear + 1) % maxSize;
}
}
}
//*************************************************************************************************************
int Tree_High(BiNode* T) //求二叉树高度的非递归算法
{
if (T == NULL)
return 0;
BiNode* queue[maxSize], * p;//定义一个循环队列,还有一个工作指针p
int front = 0, rear = 0; //初始化循环队列
queue[rear] = T;
rear = (rear + 1) % maxSize;//根结点入队
int last = rear, level = 0; //指针last指向当前层的最右结点,level是高度
while (front != rear) //队列不空时循环
{
p = queue[front];
front = (front + 1) % maxSize;//队头元素出队
if (p->lchild != NULL) //左子树不空则进队
{
queue[rear] = p->lchild;
rear = (rear + 1) % maxSize;
}
if (p->rchild != NULL)//右子树不空则进队
{
queue[rear] = p->rchild;
rear = (rear + 1) % maxSize;
}
if (front == last) //如果当前层的所有的结点已出队则高度加一,且让last指针重新指向下一层的最右结点
{
level++;
last = rear;
}
}
return level;
}
//*************************************************************************************************************
int Tree_High2(BiNode* T) //求二叉树高的递归算法
{
if (T == NULL)
return 0;
int lefthigh = 0, righthigh = 0;
lefthigh = Tree_High2(T->lchild);
righthigh = Tree_High2(T->rchild);
if (lefthigh > righthigh)
return lefthigh + 1;
else
return righthigh + 1;
}
//*************************************************************************************************************
void Tree_levelSum(BiNode* T) //求二叉树每层的结点个数
{
if (T == NULL)
return ;
BiNode* queue[maxSize], * p;//定义一个循环队列,还有一个工作指针p
int front = 0, rear = 0; ///初始化循环队列
int amount = 0, level = 0; //定义amount存放每层结点数,level是高度
queue[rear] = T;
rear = (rear + 1) % maxSize;//根结点入队
amount++; //第一层结点数加一
int last = rear;//指针last指向当前层的最右结点
printf("%s%d%s%d%s", "第", 1, "层有", amount, "个结点"); //若树不空,第一层一定只有根节点一个结点
amount = 0;//重新置为0,为下一层计数做准备
printf("\n");
while (front != rear) //队列不空时循环
{
p = queue[front];
front = (front + 1) % maxSize;//队头元素出队
if (p->lchild != NULL) //左子树不空则进队
{
queue[rear] = p->lchild;
rear = (rear + 1) % maxSize;
amount++; //有结点入队则当前层结点数加一
}
if (p->rchild != NULL)//右子树不空则进队
{
queue[rear] = p->rchild;
rear = (rear + 1) % maxSize;
amount++; //有结点入队则当前层结点数加一
}
if (front == last) //如果当前层的所有的结点已出队则高度加一,且让last指针重新指向下一层的最右结点
{
level++;
if(amount!=0) //因为树的第一层被单独处理了,所以这里不加判断会多输出一次节点数为0的情况
printf("%s%d%s%d%s", "第",level+1, "层有",amount,"个结点");
last = rear;
printf("\n");
amount = 0;
}
}
}
//*************************************************************************************************************
void FindCommonAncestor(BiNode* T, ElemType x, ElemType y,BiNode *temp1[],BiNode *temp2[])//查找两个结点的最近公共祖先
{
int top1=FindAncestorToChild(T, x,temp1);
int top2 = FindAncestorToChild(T, y, temp2);
while (temp1[top1]->data== temp2[top2]->data) //在两个栈中寻找最后一个相等的结点
{
top1--;
top2--;
}
printf("%d", temp1[++top1]->data); //两个栈顶指针和加一后都指向最近公共结点,任意选择一个打印
}
//*************************************************************************************************************
int CountDoublesonNodes(BiNode* T) //统计一棵二叉树中双分支结点的个数
{
static int count= 0; //定义为静态变量使每次递归调用函数后count的值能传递到下一次调用
if(T == NULL)
return 0;
else
{
CountDoublesonNodes(T->lchild); //统计左子树双分支结点的个数
if (T->lchild != NULL || T->rchild != NULL)
count++;
CountDoublesonNodes(T->rchild); //统计右子树双分支结点的个数
}
return count;
}
//*************************************************************************************************************
BiNode* SwapTree(BiNode* T) //交换左右子树
{
BiNode* temp = NULL;
if (T != NULL)
{
temp = T->lchild;
T->lchild = T->rchild;
T->rchild = temp;
SwapTree(T->lchild);
SwapTree(T->rchild);
}
return T;
}
//*************************************************************************************************************
void Find_Pre(BiNode* T, int k) //找先序遍历序列中第k个结点的值
{
static int count = 0;
if (T != NULL)
{
if (++count == k) //计数器的值等于k则找到结点
printf("%d\n", T->data);
Find_Pre(T->lchild, k);
Find_Pre(T->rchild, k);
}
}
//*************************************************************************************************************
void DeleteTree(BiNode* T) //删除一棵以T为根的二叉树
{
if (T != NULL)
{
DeleteTree(T->lchild); //先删除T的左子树
DeleteTree(T->rchild); //再删除T的右子树
free(T); //最后释放T结点
T = NULL; //每释放一个以T指向的结点为根的子树时一定要将T指针置空
}
}
//*************************************************************************************************************
void FindThenDelete(BiNode* T, ElemType x) //在二叉树中查找所有结点值为x的结点,并删除以其为根的子树
{
if (T == NULL) //空树直接退出
return;
if (T->data == x) //若根节点的值为x,则删除整棵树
{
DeleteTree(T);
return;
}
BiNode* queue[maxSize], * p;//定义一个循环队列,还有一个工作指针p
int front = 0, rear = 0; //初始化循环队列
queue[rear] = T;
rear = (rear + 1) % maxSize;//根结点入队
while (front != rear) //队列不空时循环
{
p = queue[front];
front = (front + 1) % maxSize;//队头元素出队
if (p->lchild != NULL) //左子树不空
{
if (p->lchild->data == x) //若左子树的结点值等于x则删除左子树
{
DeleteTree(p->lchild);
p->lchild = NULL;
}
else //否则入队
{
queue[rear] = p->lchild;
rear = (rear + 1) % maxSize;
}
}
if (p->rchild != NULL)//右子树不空
{
if (p->rchild->data == x)//右子树的结点值等于x则删除右子树
{
DeleteTree(p->rchild);
p->rchild = NULL;
}
else //否则入队
{
queue[rear] = p->rchild;
rear = (rear + 1) % maxSize;
}
}
}
}
//*************************************************************************************************************
void InThread(ThreadBiNode *&p, ThreadBiNode*& pre)
{
if (p!= NULL)
{
InThread(p->lchild, pre);
if (p->lchild == NULL)
{
p->lchild = pre;
p->ltag = 1;
}
if (pre!=NULL&&pre->rchild==NULL)
{
pre->rchild = p;
pre->rtag = 1;
}
pre = p;
InThread(p->rchild, pre);
}
}
//*************************************************************************************************************
void CreateInThread(ThreadBiNode* T)
{
ThreadBiNode* pre = NULL;
if (T != NULL)
{
InThread(T, pre);
pre->rchild = NULL;
pre->rtag = 1;
}
}
//*************************************************************************************************************
ThreadBiNode* FirstNode(ThreadBiNode* p)
{
while (p->ltag == 0)
p = p->lchild;
return p;
}
//*************************************************************************************************************
ThreadBiNode* NextNode(ThreadBiNode* p)
{
if (p->rtag == 0)
return FirstNode(p->rchild);
else
return p->rchild;
}
//*************************************************************************************************************
void ThreadInOrder(ThreadBiNode* T)
{
for (ThreadBiNode* p = FirstNode(T); p != NULL; p = NextNode(p))
printf("%d\n", p->data);
}
//*************************************************************************************************************
ThreadBiNode* InPostPre(ThreadBiNode* T, ThreadBiNode* p)//在中序线索树上求指定结点在后序前驱结点
{
ThreadBiNode* q=NULL;
if (p->rtag == 0)//若p有右子女,则右子女是其后序前驱
q = p->rchild;
else if (p->ltag == 0)//若p有左子女,则左子女是其后序前驱
q = p->lchild;
else //若p既无左子女又无右子女,则沿左线索链寻找p结点第一个出现左子女的双亲结点
{
while (p != NULL && p->ltag == 1)//直到双亲有左子女
p = p->lchild;
if (p != NULL) //双亲存在则p结点的后序前驱是其左子女
q = p->lchild;
}
return q;
}
//*************************************************************************************************************
二叉树功能测试代码
猜你喜欢
转载自blog.csdn.net/Leon1997726/article/details/100052149
今日推荐
周排行