版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/WUDAIJUN/article/details/8462610
/*
DJ.W 2012.12.06
代码功能: 将一个邻接表图转换为孩子兄弟法表示的二叉树
*/
#include <iostream>
#include <string.h>
using namespace std;
//=====Queue===============================================================================================
//队列结构:基于数组的循环队列
//元素类型:整型
typedef struct _Queue
{
int *pElemt; //数据区
int front; //指向队列首部元素
int tail; //指向当前队列尾部元素的下一个位置
int max_elemt; //最大元素个数 由使用者指定
bool bFull; //队列满标识
bool bEmpty; //队列空标识
}Queue;
//队列初始化 front为出口 tail为入口
void InitQueue(Queue &queue, const int max_element)
{
queue.pElemt = new int[max_element];
// ASSERT(queue.pElemt != NULL);
queue.front = 0;
queue.tail = 0;
queue.max_elemt = max_element;
queue.bFull = false;
queue.bEmpty = true;
}
//入队列 注意判满和标识非空
bool EnQueue(Queue &que, const int elemnt)
{
if (que.bFull)
return false;
que.pElemt[que.tail] = elemnt;
que.tail = (++que.tail)%que.max_elemt;
if (que.tail == que.front)
que.bFull = true;
que.bEmpty = false;
return true;
}
//出队列 注意判空并标识非满
bool OutQueue(Queue &que, int& element)
{
if (que.bEmpty)
return false;
element = que.pElemt[que.front];
que.front = (++que.front)%que.max_elemt;
if (que.front == que.tail)
que.bEmpty = true;
que.bFull = false;
return true;
}
//判空
bool QueueEmpty(Queue& que)
{
return que.bEmpty;
}
//销毁队列 ***
void DeQueue(Queue que)
{
delete []que.pElemt;
que.pElemt = NULL;
}
//=====Tree=========================================================================================
typedef struct _Tree
{
string strData;
struct _Tree* pLeftChild;
struct _Tree* pRightSib;
}TreeNode;
//以parent(lchild, rchild)的形式递归输出树
void DisplayTree(TreeNode* pNode)
{
if (pNode)
{
cout<<pNode->strData.c_str();
if (pNode->pLeftChild || pNode->pRightSib)
{
cout<<"(";
DisplayTree(pNode->pLeftChild);
if (pNode->pRightSib)
{
cout<<",";
DisplayTree(pNode->pRightSib);
}
cout<<")";
}
}
}
//通过顶点名字得到顶点在树中对应保存节点的指针 ******
TreeNode* GetPtrByName(TreeNode* pNode, const char* name)
{
TreeNode* pRet = NULL;
if(pNode)
{
if (!pNode->strData.compare(name))
return pNode;
else
{
if((pRet = GetPtrByName(pNode->pLeftChild, name))==NULL)
if((pRet = GetPtrByName(pNode->pRightSib, name))==NULL)
return NULL;
return pRet;
}
}
return NULL;
}
//销毁树
void DestroyTree(TreeNode* pNode)
{
if (pNode)
{
DestroyTree(pNode->pLeftChild);
DestroyTree(pNode->pRightSib);
delete pNode;
pNode = NULL;
}
}
//=====Graph========================================================================================
/*
图存储结构: 邻接表
图类型 : 默认为无向图,因此用户输入每一条边都是双向(可通过修改AddArc很方便转换为有向)
无权值
*/
//====图结构声明部分
#define MAX_VETEX_NUM 10
//边
typedef struct _Arc
{
int vetex_index;
struct _Arc* pNextArc;
}Arc;
//顶点
typedef struct _Node
{
char vetex_name[MAX_VETEX_NUM];
Arc* pFirstArc;
bool bVisited;
}Node;
//图
typedef struct _Graph
{
Node *pNode;
int nNodeNum;
int nArcNum;
}Graph;
//======图函数声明部分
//根据顶点名字name返回顶点在图graph的顶点数组中的索引
//如果不存在该顶点 返回-1
int Location(Graph& graph, char* name);
//根据用户输入初始化图
void InitGraph(Graph &graph);
//在图graph中添加 aloc---bloc边 aloc,bloc为顶点索引
void AddArc(Graph& graph, int aloc, int bloc);
//销毁图 释放节点和弧信息
void DestroyGraph(Graph &graph);
//递归销毁pArc之后的所有边
void DeleteArc(Arc* pArc);
//输出图信息
void DisplayGraph(Graph& graph);
//=====函数实现=====
void InitGraph(Graph &graph)
{
int numNode, numArc;
cout<<"input num of vetex: "<<endl;
cin>>numNode;
cout<<"input num of Arc: "<<endl;
cin>>numArc;
//根据用户输入初始化图
graph.nArcNum = numArc;
graph.nNodeNum = numNode;
graph.pNode = new Node[numNode];
//初始化顶点
cout<<"input "<<numNode<<" vetex name: (at most "<< MAX_VETEX_NUM-1<<" charactors)"<<endl;
for (int i=0; i<graph.nNodeNum; i++)
{
cin>>graph.pNode[i].vetex_name;
graph.pNode[i].bVisited = false;
}
//初始化边
for (i=0; i<graph.nNodeNum; i++)
graph.pNode[i].pFirstArc = NULL;
char a[MAX_VETEX_NUM], b[MAX_VETEX_NUM];
int aLoc, bLoc;
cout<<"input related vetexs (eg: A B):"<<endl;
for (i=0; i<graph.nArcNum; i++)
{
cout<<i+1<<": ";
cin>>a>>b;
aLoc = Location(graph, a);
bLoc = Location(graph, b);
if (aLoc == -1 || bLoc == -1 || aLoc==bLoc)
{
cout<<"error node"<<endl;
i--;
continue;
}
AddArc(graph, aLoc, bLoc);
}
}
//根据顶点名字得到顶点位置
int Location(Graph& graph, char* name)
{
for (int i=0; i<graph.nNodeNum; i++)
{
if(strcmp(graph.pNode[i].vetex_name,name) == 0)
return i;
}
return -1;
}
//添加位置为aloc, bloc的两个顶点组成的一条边
void AddArc(Graph& graph, int aloc, int bloc)
{
//添加a节点后的弧
Arc** pLastArc = &graph.pNode[aloc].pFirstArc;
while (*pLastArc)
{
pLastArc = &((*pLastArc)->pNextArc);
}
Arc *pTemp = new Arc;
pTemp->pNextArc = NULL;
pTemp->vetex_index = bloc;
*pLastArc = pTemp;
}
//销毁图
void DestroyGraph(Graph &graph)
{
Arc* pArcTemp;
//先销毁各点之后的弧节点
for (int i=0; i<graph.nNodeNum; i++)
{
pArcTemp = graph.pNode[i].pFirstArc;
DeleteArc(pArcTemp);
graph.pNode[i].pFirstArc = NULL;
}
//销毁顶点
delete[] graph.pNode;
graph.pNode = NULL;
graph.nArcNum = 0;
graph.nNodeNum = 0;
}
//删除pArc及和它具有相同弧尾的边
void DeleteArc(Arc* pArc)
{
if (pArc)
{
DeleteArc(pArc->pNextArc);
delete pArc;
}
}
//输出图信息
void DisplayGraph(Graph& graph)
{
cout<<"Vetex Information : "<<endl;
cout<<" ";
for (int i=0; i<graph.nNodeNum; i++)
{
cout<<graph.pNode[i].vetex_name<<" ";
}
cout<<endl;
cout<<"Arc Information : "<<endl;
Arc* pArc;
for (i=0; i<graph.nNodeNum; i++)
{
cout<<"For Vetex "<<graph.pNode[i].vetex_name<<": "<<endl;
pArc = graph.pNode[i].pFirstArc;
while (pArc)
{
cout<<" "<<graph.pNode[i].vetex_name<<"---"\
<<graph.pNode[pArc->vetex_index].vetex_name<<endl;
pArc = pArc->pNextArc;
}
}
}
//队列功能测试
void QueueTest()
{
Queue que;
int size;
cout<<"input size of queue : "<<endl;
cin>>size;
InitQueue(que, size);
cout<<"function select : "<<endl;
cout<<"1: EnQueue. 2:OutQueue. 0:Exit"<<endl;
cout<<"your choice : ";
int choice;
int elemTemp;
cin>>choice;
while(true)
{
switch(choice)
{
case 0: //退出选项在switch外判断 直接break跳出while
break;
case 1:
cout<<"input elem data : ";
cin>>elemTemp;
if(!EnQueue(que, elemTemp))
cout<<"Error : The queue is empty now! "<<endl;
break;
case 2:
if(!OutQueue(que, elemTemp))
{
cout<<"Error : The queue is full now!"<<endl;
break;
}
cout<<"Out elem is "<<elemTemp<<endl;
break;
default:
cout<<"1: EnQueue. 2:OutQueue. 0:Exit. Input 0, 1 or 2"<<endl;
break;
}
if(!choice)
break;
cout<<"Next Operation: ";
cin>>choice;
}
DeQueue(que);
}
//图功能测试
void GraphTest()
{
Graph graph;
InitGraph(graph);
DisplayGraph(graph);
DestroyGraph(graph);
}
/*
通过广度优先遍历的方式将图转换为二叉树
*/
void GraphToTree_BFS(Graph& graph, TreeNode* &pt)
{
//建立队列
Queue que;
InitQueue(que, graph.nNodeNum+1);
//这两个指针用于跟踪当前活动的左子树和右子树
TreeNode* pCurLeftChild = pt, *pCurRightSib = pt;
Arc* pArc = NULL;
for (int i=0; i<graph.nNodeNum; i++)
{
if (graph.pNode[i].bVisited)
continue;
//跟踪建立树
if (i == 0)
{
//第一个顶点 即为根节点
pt = new TreeNode;
pt->strData = graph.pNode[i].vetex_name;
pt->pLeftChild = NULL;
pt->pRightSib = NULL;
pCurLeftChild = pt;
pCurRightSib = pt;
}
else
{
//其他顶点 插在第一个顶点即根节点之后
pCurRightSib->pRightSib = new TreeNode;
pCurRightSib->pRightSib->strData = graph.pNode[i].vetex_name;
pCurRightSib->pRightSib->pLeftChild = NULL;
pCurRightSib->pRightSib->pRightSib = NULL;
pCurRightSib = pCurRightSib->pRightSib;
}
//顶点入队 标记
graph.pNode[i].bVisited = true;
EnQueue(que, i);
int nextnode;
//依次弹出队列中各个已经访问过的顶点 遍历访问他们的邻接点
while(!QueueEmpty(que))
{
//根据队列中弹出的元素 修改当前活跃的左子树和右子树(pCurLeftChild pCurRightSib)
OutQueue(que, nextnode);
TreeNode* pTemp = GetPtrByName(pt, graph.pNode[nextnode].vetex_name);
pCurLeftChild = pTemp;
pCurRightSib = pTemp;
//遍历该顶点的边。并插到pCurLeftChild的左子树(如果是第一个顶点)或pCurRightSib的右子树(如果是其他顶点)
bool bFirstNode = true;
for(Arc* pArc=graph.pNode[nextnode].pFirstArc; \
pArc; pArc=pArc->pNextArc)
{
int ArcIndex = pArc->vetex_index;
if (!graph.pNode[ArcIndex].bVisited)
{
if (bFirstNode)
{
//插到当前活跃的左子树左孩子
pCurLeftChild->pLeftChild = new TreeNode;
pCurLeftChild->pLeftChild->strData = graph.pNode[ArcIndex].vetex_name;
pCurLeftChild->pLeftChild->pLeftChild = NULL;
pCurLeftChild->pLeftChild->pRightSib = NULL;
pCurLeftChild = pCurLeftChild->pLeftChild;
bFirstNode = false;
//修改当前活跃的右子树(因为之后的顶点均为pCurLeftChild的兄弟节点 应放在pCurLeftChild的右孩子)
pCurRightSib = pCurLeftChild;
}
else
{
//插到当前活跃右子树的右孩子
pCurRightSib->pRightSib = new TreeNode;
pCurRightSib->pRightSib->strData = graph.pNode[ArcIndex].vetex_name;
pCurRightSib->pRightSib->pLeftChild = NULL;
pCurRightSib->pRightSib->pRightSib = NULL;
pCurRightSib = pCurRightSib->pRightSib;
}
//入队 并标记
graph.pNode[ArcIndex].bVisited = true;
EnQueue(que, ArcIndex);
}
}
}
//当栈为空时。说明一个连通分支遍历完毕 此时应该恢复pCurLeftChild和pCurRightSib到根节点
pCurLeftChild = pt;
pCurRightSib = pt;
}
//销毁队列
DeQueue(que);
}
int main()
{
//GraphTest();
//QueueTest();
TreeNode* pt = NULL;
Graph graph;
InitGraph(graph);
GraphToTree_BFS(graph, pt);
cout<<endl;
cout<<"============RESULT=================="<<endl;
DisplayTree(pt);
cout<<endl;
cout<<"===================================="<<endl;
DestroyGraph(graph);
DestroyTree(pt);
return 0;
}