Graph数据结构图操作课设.docx
《Graph数据结构图操作课设.docx》由会员分享,可在线阅读,更多相关《Graph数据结构图操作课设.docx(34页珍藏版)》请在冰豆网上搜索。
Graph数据结构图操作课设
//Graph.cpp:
implementationoftheCGraphclass.
//
//////////////////////////////////////////////////////////////////////
#include"stdafx.h"
#pragmawarning(disable:
4786)
#include
usingstd:
:
deque;
vector;
#include"景区旅游信息管理系统.h"
#include"Graph.h"
#include"PathDlg.h"
#ifdef_DEBUG
#undefTHIS_FILE
staticcharTHIS_FILE[]=__FILE__;
#definenewDEBUG_NEW
#endif
//Construction/Destruction
externCMyApptheApp;
CGraph:
CGraph()
{
}
~CGraph()
voidCGraph:
AddOneNode(CNode*pNewNode)
this->m_nodeArray.Add(*pNewNode);
//新增一条边
AddOneEdge(CEdge*pNewEdge)
this->m_edgeArray.Add(*pNewEdge);
//删除一个结点,以及相关联的边
DeleteOneNodeByPtr(CNode*pNode)
//1先删除相关联的边
this->DeleteEdgesAcrossOneNode(pNode);
//2删除结点
intsize=this->m_nodeArray.GetSize();
for(inti=0;i{if(pNode==&m_nodeArray[i]){this->m_nodeArray.RemoveAt(i);break;}}//ASSERT(i!=size);}//删除一条边voidCGraph::DeleteOneEdgeByPtr(CEdge*pEdge){intsize=this->m_edgeArray.GetSize();for(inti=0;i{if(pEdge==&m_edgeArray[i]){this->DeleteOneEdgeByNoInArray(i);break;}}//ASSERT(i!=size);}voidCGraph::DeleteOneEdgeByNoInArray(inti){this->m_edgeArray.RemoveAt(i);}//如果这条边与结点pNode相关联,删除voidCGraph::DeleteEdgesAcrossOneNode(CNode*pNode){intsize=this->m_edgeArray.GetSize();for(inti=0;i{CEdgepe=this->m_edgeArray.GetAt(i);if(pe.m_nodeIndex1==pNode->m_nodeIndex||pe.m_nodeIndex2==pNode->m_nodeIndex){CStringstr;str="从"+this->GetOneNodeByIndex(m_edgeArray.GetAt(i).m_nodeIndex1)->m_nodeName+"到"+this->GetOneNodeByIndex(m_edgeArray.GetAt(i).m_nodeIndex2)->m_nodeName+"的边也被删除!";AfxMessageBox(str);this->DeleteOneEdgeByNoInArray(i);size--;i--;}}}CEdge*CGraph::GetOneEdgeBy2Nodes(CNode*sideNode1,CNode*sideNode2){ASSERT(sideNode1!=NULL);ASSERT(sideNode2!=NULL);intsize=this->m_edgeArray.GetSize();for(inti=0;i{if(this->m_edgeArray.GetAt(i).m_nodeIndex1==sideNode1->m_nodeIndex){if(m_edgeArray.GetAt(i).m_nodeIndex2==sideNode2->m_nodeIndex)return&this->m_edgeArray[i];}elseif(this->m_edgeArray.GetAt(i).m_nodeIndex1==sideNode2->m_nodeIndex){if(m_edgeArray.GetAt(i).m_nodeIndex2==sideNode1->m_nodeIndex)return&this->m_edgeArray[i];}elsecontinue;}returnNULL;}//由索引值得到一个结点的地址,如果没有就返回NULL。CNode*CGraph::GetOneNodeByIndex(intindex){intsize=this->m_nodeArray.GetSize();for(inti=0;i{if(this->m_nodeArray.GetAt(i).m_nodeIndex==index){return&m_nodeArray[i];}}returnNULL;}/////////////////////////////////////////////////////////////////////////////////////////////生成导游图!//////////////////////////////////////////////////////////////////////////////////////////////[参数]:nIndexStart入口结点索引值//nIndexEnd出品结点索引值,0代表任意的//入口或出口结点都可做为出口////[返回]:生成成功返回true,否则返回false;////[数据结构要求]://能够从一个结点得到它的所有的有边相连的其它结点,在这里使用邻接表.//用树来表示所有可能的路线方案集合////ALGraph:表示用邻接表表示成的图//AdList:typedefCListAdList;//邻接表中的一条链表,表头表示图中一个顶点,链表中的其它//元素表示它们与该顶点之间的边关系//EdgeNode:邻接表中的一个元素,表示从一个结点到它相邻的结点及其边////Tree:用来描述一棵树,代表其中的一个结点//dequeactiveNode:用来记录在生成这棵树的过程中,当前有哪些结点正//在等待生成子结点。一旦它生成了它的子结点(与它//相邻的那些结点),它就变成了一个父结点,也将从//activeNode队列中删除,并将它生成的那些子结点再//加入activeNode队列当中去。///*[关于树结构的问题]:如果使用在栈上生成Tree的话,就会造成一出Tree的作用域,将自动析构。因此这里采用new的方法在堆上生成树结点。为了解决内存释放,在这里将每次new出来的Tree*的地址保存起来,这样在最后只要将保存在数组里面的Tree给全部释放掉即可。*/boolCGraph::CreateGuideMap(intnIndexStart,intnIndexEnd){CWaitCursormake_a_wait_cursor_during_this_function;//创建邻接表ALGraphg;this->CreateAdjacencyListGraph(g);if(this->IsConnectedGraph(g)==false)//连通图{AfxMessageBox("该图不是一个连通图\n路径配置出错\n请联系管理员");theApp.SetCurrentStatus(Normal);returnfalse;}/*//开始创建搜索树!Tree*root=newTree;allTreeItemPtrArray.push_back(root);root->nPathLength=0;root->pNode=this->GetOneNodeByIndex(nIndexStart);root->pParent=NULL;root->pEdge=NULL;activeNodeDeque.push_back(root);*/dequeactiveNodeDeque;//队列用来记录还未扩展的结点//theApp.SetCurrentStatus(Normal);vectorbestGuideMap;//保存搜索到的最优路径!vector>bestGuideMaps;//保存所有的最优路径!doublebestLength=-1;//初使化最短路径长度为-1vectorallTreeItemPtrArray;//用一个数组来记录所有new出来的Tree,以便于释放//开始创建搜索树!Tree*root=newTree;allTreeItemPtrArray.push_back(root);root->nPathLength=0;root->pNode=this->GetOneNodeByIndex(nIndexStart);root->pParent=NULL;root->pEdge=NULL;activeNodeDeque.push_back(root);while(activeNodeDeque.size()!=0){//取出队列中的头一个结点,作为父结点Tree*parentNode=activeNodeDeque[0];//从邻接表中得到该结点的边,生成子结点intindex=g.GetNodeIndex(parentNode->pNode);ASSERT(index!=-1);//链表中第一个结点为本身,后面的为与其相邻接的边POSITIONpos=g.pList[index].GetHeadPosition();g.pList[index].GetNext(pos);//第一个结点不是边while(pos!=NULL){//在邻接表中获取下一个相邻结点,在树中生成子结点EdgeNodeen=g.pList[index].GetNext(pos);//[裁枝]:如果这条新路径的长度已经大于最短路径,忽略if(bestLength!=-1&&(parentNode->nPathLength+en.pEdge->m_pathLength)>bestLength)continue;//[裁枝]:如果再走了一回重复的路(如1-2-1-2,不考虑1-2-3-2-1-2-3,或更多重复)Tree*gradeParentTree=parentNode->pParent;if(gradeParentTree!=NULL){if(en.pNode==gradeParentTree->pNode){Tree*gradeGradeParentTree=gradeParentTree->pParent;if(gradeGradeParentTree!=NULL){if(parentNode->pNode==gradeGradeParentTree->pNode)continue;}}}//创建一个新的树结点Tree*pTreeNode=newTree;if(pTreeNode==NULL){AfxMessageBox("创建对象失败,堆内存不足...");gotoEND;}allTreeItemPtrArray.push_back(pTreeNode);pTreeNode->nPathLength=parentNode->nPathLength+en.pEdge->m_pathLength;pTreeNode->pNode=en.pNode;pTreeNode->pParent=parentNode;pTreeNode->pEdge=en.pEdge;TRACE2("生成<%s>的子树<%s>\n",parentNode->pNode->m_nodeName,pTreeNode->pNode->m_nodeName);//加入活动结点activeNodeDeque.push_back(pTreeNode);TRACE1("入队:<%s>\n",pTreeNode->pNode->m_nodeName);//出口判断if(endPointTest(pTreeNode,nIndexEnd)){TRACE0("找到一条向导路径!下一步该进行裁枝了!\n");boolneed=false;//是否需要重新裁枝bestGuideMap.clear();if(pTreeNode->nPathLength{need=true;//找到一条最优路径bestLength=pTreeNode->nPathLength;bestGuideMaps.clear();Tree*pTemp=pTreeNode;while(pTemp!=NULL){bestGuideMap.push_back(pTemp);pTemp=pTemp->pParent;}bestGuideMaps.push_back(bestGuideMap);}elseif(pTreeNode->nPathLength==bestLength){//找到一另外一条最短路径Tree*pTemp=pTreeNode;while(pTemp!=NULL){bestGuideMap.push_back(pTemp);pTemp=pTemp->pParent;}bestGuideMaps.push_back(bestGuideMap);}else{activeNodeDeque.pop_back();//刚放队列的这条路径不会是最优路径,删除continue;}//关于怎么裁枝:<将其它路径长度已经大于最优路径的长度的子树删除>//只要将活动结点队列中大于最优长度的结点从活动结点队列中删除就行了//因为当活动结点队列为空,整个搜索过程就结束了//删除时不去查看队列中的第一个,因为正在处理它,从第二个开始算起if(need==false)//不需要再裁枝continue;if(activeNodeDeque.size()<2)continue;std::deque::iteratoriter=activeNodeDeque.begin();std::deque::iteratoriterEnd=activeNodeDeque.end();iter++;for(;iter!=iterEnd;iter++){if((*iter)->nPathLength>pTreeNode->nPathLength)//删除掉这个活动结点{ASSERT((*iter)->nPathLength!=0);TRACE1("删除一个活动结点:\t%f\n",(*iter)->nPathLength);activeNodeDeque.erase(iter);//iter,iterEnd被破坏了...重新获取iter=activeNodeDeque.begin();iter++;iterEnd=activeNodeDeque.end();}}}}//父结点处理完毕,从活动结点删除activeNodeDeque.pop_front();}END://输出最优路径CPathDlgdlg((DWORD)&bestGuideMaps,(DWORD)this);dlg.DoModal();//内存释放//释放剩余资源intptrCount=allTreeItemPtrArray.size();for(intj=0;j{deleteallTreeItemPtrArray[j];}allTreeItemPtrArray.clear();//退出向导模式theApp.SetCurrentStatus(Normal);returntrue;}//在这里用来生成邻接链表!voidCGraph::CreateAdjacencyListGraph(ALGraph&g){//1,纵向添加头结点intsize=this->m_nodeArray.GetSize();g.pList=newAdList[size];g.nNodeCount=size;for(inti=0;i{EdgeNodeen;en.pNode=&this->m_nodeArray[i];//保存地址,用地址来存储g.pList[i].AddHead(en);}//2,横向添加边intedgeSize=this->m_edgeArray.GetSize();for(intj=0;j{CNode*sideNode1=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex1);CNode*sideNode2=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex2);//两个端点分别添加一次for(intk=0;kif(g.pList[k].GetHead().pNode==sideNode1){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode2;g.pList[k].AddTail(node);break;}for(intl=0;lif(g.pList[l].GetHead().pNode==sideNode2){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode1;g.pList[l].AddTail(node);break;}}}/***************************************************************
if(pNode==&m_nodeArray[i])
this->m_nodeArray.RemoveAt(i);
break;
//ASSERT(i!
=size);
//删除一条边
DeleteOneEdgeByPtr(CEdge*pEdge)
intsize=this->m_edgeArray.GetSize();
for(inti=0;i{if(pEdge==&m_edgeArray[i]){this->DeleteOneEdgeByNoInArray(i);break;}}//ASSERT(i!=size);}voidCGraph::DeleteOneEdgeByNoInArray(inti){this->m_edgeArray.RemoveAt(i);}//如果这条边与结点pNode相关联,删除voidCGraph::DeleteEdgesAcrossOneNode(CNode*pNode){intsize=this->m_edgeArray.GetSize();for(inti=0;i{CEdgepe=this->m_edgeArray.GetAt(i);if(pe.m_nodeIndex1==pNode->m_nodeIndex||pe.m_nodeIndex2==pNode->m_nodeIndex){CStringstr;str="从"+this->GetOneNodeByIndex(m_edgeArray.GetAt(i).m_nodeIndex1)->m_nodeName+"到"+this->GetOneNodeByIndex(m_edgeArray.GetAt(i).m_nodeIndex2)->m_nodeName+"的边也被删除!";AfxMessageBox(str);this->DeleteOneEdgeByNoInArray(i);size--;i--;}}}CEdge*CGraph::GetOneEdgeBy2Nodes(CNode*sideNode1,CNode*sideNode2){ASSERT(sideNode1!=NULL);ASSERT(sideNode2!=NULL);intsize=this->m_edgeArray.GetSize();for(inti=0;i{if(this->m_edgeArray.GetAt(i).m_nodeIndex1==sideNode1->m_nodeIndex){if(m_edgeArray.GetAt(i).m_nodeIndex2==sideNode2->m_nodeIndex)return&this->m_edgeArray[i];}elseif(this->m_edgeArray.GetAt(i).m_nodeIndex1==sideNode2->m_nodeIndex){if(m_edgeArray.GetAt(i).m_nodeIndex2==sideNode1->m_nodeIndex)return&this->m_edgeArray[i];}elsecontinue;}returnNULL;}//由索引值得到一个结点的地址,如果没有就返回NULL。CNode*CGraph::GetOneNodeByIndex(intindex){intsize=this->m_nodeArray.GetSize();for(inti=0;i{if(this->m_nodeArray.GetAt(i).m_nodeIndex==index){return&m_nodeArray[i];}}returnNULL;}/////////////////////////////////////////////////////////////////////////////////////////////生成导游图!//////////////////////////////////////////////////////////////////////////////////////////////[参数]:nIndexStart入口结点索引值//nIndexEnd出品结点索引值,0代表任意的//入口或出口结点都可做为出口////[返回]:生成成功返回true,否则返回false;////[数据结构要求]://能够从一个结点得到它的所有的有边相连的其它结点,在这里使用邻接表.//用树来表示所有可能的路线方案集合////ALGraph:表示用邻接表表示成的图//AdList:typedefCListAdList;//邻接表中的一条链表,表头表示图中一个顶点,链表中的其它//元素表示它们与该顶点之间的边关系//EdgeNode:邻接表中的一个元素,表示从一个结点到它相邻的结点及其边////Tree:用来描述一棵树,代表其中的一个结点//dequeactiveNode:用来记录在生成这棵树的过程中,当前有哪些结点正//在等待生成子结点。一旦它生成了它的子结点(与它//相邻的那些结点),它就变成了一个父结点,也将从//activeNode队列中删除,并将它生成的那些子结点再//加入activeNode队列当中去。///*[关于树结构的问题]:如果使用在栈上生成Tree的话,就会造成一出Tree的作用域,将自动析构。因此这里采用new的方法在堆上生成树结点。为了解决内存释放,在这里将每次new出来的Tree*的地址保存起来,这样在最后只要将保存在数组里面的Tree给全部释放掉即可。*/boolCGraph::CreateGuideMap(intnIndexStart,intnIndexEnd){CWaitCursormake_a_wait_cursor_during_this_function;//创建邻接表ALGraphg;this->CreateAdjacencyListGraph(g);if(this->IsConnectedGraph(g)==false)//连通图{AfxMessageBox("该图不是一个连通图\n路径配置出错\n请联系管理员");theApp.SetCurrentStatus(Normal);returnfalse;}/*//开始创建搜索树!Tree*root=newTree;allTreeItemPtrArray.push_back(root);root->nPathLength=0;root->pNode=this->GetOneNodeByIndex(nIndexStart);root->pParent=NULL;root->pEdge=NULL;activeNodeDeque.push_back(root);*/dequeactiveNodeDeque;//队列用来记录还未扩展的结点//theApp.SetCurrentStatus(Normal);vectorbestGuideMap;//保存搜索到的最优路径!vector>bestGuideMaps;//保存所有的最优路径!doublebestLength=-1;//初使化最短路径长度为-1vectorallTreeItemPtrArray;//用一个数组来记录所有new出来的Tree,以便于释放//开始创建搜索树!Tree*root=newTree;allTreeItemPtrArray.push_back(root);root->nPathLength=0;root->pNode=this->GetOneNodeByIndex(nIndexStart);root->pParent=NULL;root->pEdge=NULL;activeNodeDeque.push_back(root);while(activeNodeDeque.size()!=0){//取出队列中的头一个结点,作为父结点Tree*parentNode=activeNodeDeque[0];//从邻接表中得到该结点的边,生成子结点intindex=g.GetNodeIndex(parentNode->pNode);ASSERT(index!=-1);//链表中第一个结点为本身,后面的为与其相邻接的边POSITIONpos=g.pList[index].GetHeadPosition();g.pList[index].GetNext(pos);//第一个结点不是边while(pos!=NULL){//在邻接表中获取下一个相邻结点,在树中生成子结点EdgeNodeen=g.pList[index].GetNext(pos);//[裁枝]:如果这条新路径的长度已经大于最短路径,忽略if(bestLength!=-1&&(parentNode->nPathLength+en.pEdge->m_pathLength)>bestLength)continue;//[裁枝]:如果再走了一回重复的路(如1-2-1-2,不考虑1-2-3-2-1-2-3,或更多重复)Tree*gradeParentTree=parentNode->pParent;if(gradeParentTree!=NULL){if(en.pNode==gradeParentTree->pNode){Tree*gradeGradeParentTree=gradeParentTree->pParent;if(gradeGradeParentTree!=NULL){if(parentNode->pNode==gradeGradeParentTree->pNode)continue;}}}//创建一个新的树结点Tree*pTreeNode=newTree;if(pTreeNode==NULL){AfxMessageBox("创建对象失败,堆内存不足...");gotoEND;}allTreeItemPtrArray.push_back(pTreeNode);pTreeNode->nPathLength=parentNode->nPathLength+en.pEdge->m_pathLength;pTreeNode->pNode=en.pNode;pTreeNode->pParent=parentNode;pTreeNode->pEdge=en.pEdge;TRACE2("生成<%s>的子树<%s>\n",parentNode->pNode->m_nodeName,pTreeNode->pNode->m_nodeName);//加入活动结点activeNodeDeque.push_back(pTreeNode);TRACE1("入队:<%s>\n",pTreeNode->pNode->m_nodeName);//出口判断if(endPointTest(pTreeNode,nIndexEnd)){TRACE0("找到一条向导路径!下一步该进行裁枝了!\n");boolneed=false;//是否需要重新裁枝bestGuideMap.clear();if(pTreeNode->nPathLength{need=true;//找到一条最优路径bestLength=pTreeNode->nPathLength;bestGuideMaps.clear();Tree*pTemp=pTreeNode;while(pTemp!=NULL){bestGuideMap.push_back(pTemp);pTemp=pTemp->pParent;}bestGuideMaps.push_back(bestGuideMap);}elseif(pTreeNode->nPathLength==bestLength){//找到一另外一条最短路径Tree*pTemp=pTreeNode;while(pTemp!=NULL){bestGuideMap.push_back(pTemp);pTemp=pTemp->pParent;}bestGuideMaps.push_back(bestGuideMap);}else{activeNodeDeque.pop_back();//刚放队列的这条路径不会是最优路径,删除continue;}//关于怎么裁枝:<将其它路径长度已经大于最优路径的长度的子树删除>//只要将活动结点队列中大于最优长度的结点从活动结点队列中删除就行了//因为当活动结点队列为空,整个搜索过程就结束了//删除时不去查看队列中的第一个,因为正在处理它,从第二个开始算起if(need==false)//不需要再裁枝continue;if(activeNodeDeque.size()<2)continue;std::deque::iteratoriter=activeNodeDeque.begin();std::deque::iteratoriterEnd=activeNodeDeque.end();iter++;for(;iter!=iterEnd;iter++){if((*iter)->nPathLength>pTreeNode->nPathLength)//删除掉这个活动结点{ASSERT((*iter)->nPathLength!=0);TRACE1("删除一个活动结点:\t%f\n",(*iter)->nPathLength);activeNodeDeque.erase(iter);//iter,iterEnd被破坏了...重新获取iter=activeNodeDeque.begin();iter++;iterEnd=activeNodeDeque.end();}}}}//父结点处理完毕,从活动结点删除activeNodeDeque.pop_front();}END://输出最优路径CPathDlgdlg((DWORD)&bestGuideMaps,(DWORD)this);dlg.DoModal();//内存释放//释放剩余资源intptrCount=allTreeItemPtrArray.size();for(intj=0;j{deleteallTreeItemPtrArray[j];}allTreeItemPtrArray.clear();//退出向导模式theApp.SetCurrentStatus(Normal);returntrue;}//在这里用来生成邻接链表!voidCGraph::CreateAdjacencyListGraph(ALGraph&g){//1,纵向添加头结点intsize=this->m_nodeArray.GetSize();g.pList=newAdList[size];g.nNodeCount=size;for(inti=0;i{EdgeNodeen;en.pNode=&this->m_nodeArray[i];//保存地址,用地址来存储g.pList[i].AddHead(en);}//2,横向添加边intedgeSize=this->m_edgeArray.GetSize();for(intj=0;j{CNode*sideNode1=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex1);CNode*sideNode2=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex2);//两个端点分别添加一次for(intk=0;kif(g.pList[k].GetHead().pNode==sideNode1){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode2;g.pList[k].AddTail(node);break;}for(intl=0;lif(g.pList[l].GetHead().pNode==sideNode2){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode1;g.pList[l].AddTail(node);break;}}}/***************************************************************
if(pEdge==&m_edgeArray[i])
this->DeleteOneEdgeByNoInArray(i);
DeleteOneEdgeByNoInArray(inti)
this->m_edgeArray.RemoveAt(i);
//如果这条边与结点pNode相关联,删除
DeleteEdgesAcrossOneNode(CNode*pNode)
for(inti=0;i{CEdgepe=this->m_edgeArray.GetAt(i);if(pe.m_nodeIndex1==pNode->m_nodeIndex||pe.m_nodeIndex2==pNode->m_nodeIndex){CStringstr;str="从"+this->GetOneNodeByIndex(m_edgeArray.GetAt(i).m_nodeIndex1)->m_nodeName+"到"+this->GetOneNodeByIndex(m_edgeArray.GetAt(i).m_nodeIndex2)->m_nodeName+"的边也被删除!";AfxMessageBox(str);this->DeleteOneEdgeByNoInArray(i);size--;i--;}}}CEdge*CGraph::GetOneEdgeBy2Nodes(CNode*sideNode1,CNode*sideNode2){ASSERT(sideNode1!=NULL);ASSERT(sideNode2!=NULL);intsize=this->m_edgeArray.GetSize();for(inti=0;i{if(this->m_edgeArray.GetAt(i).m_nodeIndex1==sideNode1->m_nodeIndex){if(m_edgeArray.GetAt(i).m_nodeIndex2==sideNode2->m_nodeIndex)return&this->m_edgeArray[i];}elseif(this->m_edgeArray.GetAt(i).m_nodeIndex1==sideNode2->m_nodeIndex){if(m_edgeArray.GetAt(i).m_nodeIndex2==sideNode1->m_nodeIndex)return&this->m_edgeArray[i];}elsecontinue;}returnNULL;}//由索引值得到一个结点的地址,如果没有就返回NULL。CNode*CGraph::GetOneNodeByIndex(intindex){intsize=this->m_nodeArray.GetSize();for(inti=0;i{if(this->m_nodeArray.GetAt(i).m_nodeIndex==index){return&m_nodeArray[i];}}returnNULL;}/////////////////////////////////////////////////////////////////////////////////////////////生成导游图!//////////////////////////////////////////////////////////////////////////////////////////////[参数]:nIndexStart入口结点索引值//nIndexEnd出品结点索引值,0代表任意的//入口或出口结点都可做为出口////[返回]:生成成功返回true,否则返回false;////[数据结构要求]://能够从一个结点得到它的所有的有边相连的其它结点,在这里使用邻接表.//用树来表示所有可能的路线方案集合////ALGraph:表示用邻接表表示成的图//AdList:typedefCListAdList;//邻接表中的一条链表,表头表示图中一个顶点,链表中的其它//元素表示它们与该顶点之间的边关系//EdgeNode:邻接表中的一个元素,表示从一个结点到它相邻的结点及其边////Tree:用来描述一棵树,代表其中的一个结点//dequeactiveNode:用来记录在生成这棵树的过程中,当前有哪些结点正//在等待生成子结点。一旦它生成了它的子结点(与它//相邻的那些结点),它就变成了一个父结点,也将从//activeNode队列中删除,并将它生成的那些子结点再//加入activeNode队列当中去。///*[关于树结构的问题]:如果使用在栈上生成Tree的话,就会造成一出Tree的作用域,将自动析构。因此这里采用new的方法在堆上生成树结点。为了解决内存释放,在这里将每次new出来的Tree*的地址保存起来,这样在最后只要将保存在数组里面的Tree给全部释放掉即可。*/boolCGraph::CreateGuideMap(intnIndexStart,intnIndexEnd){CWaitCursormake_a_wait_cursor_during_this_function;//创建邻接表ALGraphg;this->CreateAdjacencyListGraph(g);if(this->IsConnectedGraph(g)==false)//连通图{AfxMessageBox("该图不是一个连通图\n路径配置出错\n请联系管理员");theApp.SetCurrentStatus(Normal);returnfalse;}/*//开始创建搜索树!Tree*root=newTree;allTreeItemPtrArray.push_back(root);root->nPathLength=0;root->pNode=this->GetOneNodeByIndex(nIndexStart);root->pParent=NULL;root->pEdge=NULL;activeNodeDeque.push_back(root);*/dequeactiveNodeDeque;//队列用来记录还未扩展的结点//theApp.SetCurrentStatus(Normal);vectorbestGuideMap;//保存搜索到的最优路径!vector>bestGuideMaps;//保存所有的最优路径!doublebestLength=-1;//初使化最短路径长度为-1vectorallTreeItemPtrArray;//用一个数组来记录所有new出来的Tree,以便于释放//开始创建搜索树!Tree*root=newTree;allTreeItemPtrArray.push_back(root);root->nPathLength=0;root->pNode=this->GetOneNodeByIndex(nIndexStart);root->pParent=NULL;root->pEdge=NULL;activeNodeDeque.push_back(root);while(activeNodeDeque.size()!=0){//取出队列中的头一个结点,作为父结点Tree*parentNode=activeNodeDeque[0];//从邻接表中得到该结点的边,生成子结点intindex=g.GetNodeIndex(parentNode->pNode);ASSERT(index!=-1);//链表中第一个结点为本身,后面的为与其相邻接的边POSITIONpos=g.pList[index].GetHeadPosition();g.pList[index].GetNext(pos);//第一个结点不是边while(pos!=NULL){//在邻接表中获取下一个相邻结点,在树中生成子结点EdgeNodeen=g.pList[index].GetNext(pos);//[裁枝]:如果这条新路径的长度已经大于最短路径,忽略if(bestLength!=-1&&(parentNode->nPathLength+en.pEdge->m_pathLength)>bestLength)continue;//[裁枝]:如果再走了一回重复的路(如1-2-1-2,不考虑1-2-3-2-1-2-3,或更多重复)Tree*gradeParentTree=parentNode->pParent;if(gradeParentTree!=NULL){if(en.pNode==gradeParentTree->pNode){Tree*gradeGradeParentTree=gradeParentTree->pParent;if(gradeGradeParentTree!=NULL){if(parentNode->pNode==gradeGradeParentTree->pNode)continue;}}}//创建一个新的树结点Tree*pTreeNode=newTree;if(pTreeNode==NULL){AfxMessageBox("创建对象失败,堆内存不足...");gotoEND;}allTreeItemPtrArray.push_back(pTreeNode);pTreeNode->nPathLength=parentNode->nPathLength+en.pEdge->m_pathLength;pTreeNode->pNode=en.pNode;pTreeNode->pParent=parentNode;pTreeNode->pEdge=en.pEdge;TRACE2("生成<%s>的子树<%s>\n",parentNode->pNode->m_nodeName,pTreeNode->pNode->m_nodeName);//加入活动结点activeNodeDeque.push_back(pTreeNode);TRACE1("入队:<%s>\n",pTreeNode->pNode->m_nodeName);//出口判断if(endPointTest(pTreeNode,nIndexEnd)){TRACE0("找到一条向导路径!下一步该进行裁枝了!\n");boolneed=false;//是否需要重新裁枝bestGuideMap.clear();if(pTreeNode->nPathLength{need=true;//找到一条最优路径bestLength=pTreeNode->nPathLength;bestGuideMaps.clear();Tree*pTemp=pTreeNode;while(pTemp!=NULL){bestGuideMap.push_back(pTemp);pTemp=pTemp->pParent;}bestGuideMaps.push_back(bestGuideMap);}elseif(pTreeNode->nPathLength==bestLength){//找到一另外一条最短路径Tree*pTemp=pTreeNode;while(pTemp!=NULL){bestGuideMap.push_back(pTemp);pTemp=pTemp->pParent;}bestGuideMaps.push_back(bestGuideMap);}else{activeNodeDeque.pop_back();//刚放队列的这条路径不会是最优路径,删除continue;}//关于怎么裁枝:<将其它路径长度已经大于最优路径的长度的子树删除>//只要将活动结点队列中大于最优长度的结点从活动结点队列中删除就行了//因为当活动结点队列为空,整个搜索过程就结束了//删除时不去查看队列中的第一个,因为正在处理它,从第二个开始算起if(need==false)//不需要再裁枝continue;if(activeNodeDeque.size()<2)continue;std::deque::iteratoriter=activeNodeDeque.begin();std::deque::iteratoriterEnd=activeNodeDeque.end();iter++;for(;iter!=iterEnd;iter++){if((*iter)->nPathLength>pTreeNode->nPathLength)//删除掉这个活动结点{ASSERT((*iter)->nPathLength!=0);TRACE1("删除一个活动结点:\t%f\n",(*iter)->nPathLength);activeNodeDeque.erase(iter);//iter,iterEnd被破坏了...重新获取iter=activeNodeDeque.begin();iter++;iterEnd=activeNodeDeque.end();}}}}//父结点处理完毕,从活动结点删除activeNodeDeque.pop_front();}END://输出最优路径CPathDlgdlg((DWORD)&bestGuideMaps,(DWORD)this);dlg.DoModal();//内存释放//释放剩余资源intptrCount=allTreeItemPtrArray.size();for(intj=0;j{deleteallTreeItemPtrArray[j];}allTreeItemPtrArray.clear();//退出向导模式theApp.SetCurrentStatus(Normal);returntrue;}//在这里用来生成邻接链表!voidCGraph::CreateAdjacencyListGraph(ALGraph&g){//1,纵向添加头结点intsize=this->m_nodeArray.GetSize();g.pList=newAdList[size];g.nNodeCount=size;for(inti=0;i{EdgeNodeen;en.pNode=&this->m_nodeArray[i];//保存地址,用地址来存储g.pList[i].AddHead(en);}//2,横向添加边intedgeSize=this->m_edgeArray.GetSize();for(intj=0;j{CNode*sideNode1=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex1);CNode*sideNode2=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex2);//两个端点分别添加一次for(intk=0;kif(g.pList[k].GetHead().pNode==sideNode1){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode2;g.pList[k].AddTail(node);break;}for(intl=0;lif(g.pList[l].GetHead().pNode==sideNode2){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode1;g.pList[l].AddTail(node);break;}}}/***************************************************************
CEdgepe=this->m_edgeArray.GetAt(i);
if(pe.m_nodeIndex1==pNode->m_nodeIndex||
pe.m_nodeIndex2==pNode->m_nodeIndex)
CStringstr;
str="从"+this->GetOneNodeByIndex(m_edgeArray.GetAt(i).m_nodeIndex1)->m_nodeName
+"到"+this->GetOneNodeByIndex(m_edgeArray.GetAt(i).m_nodeIndex2)->m_nodeName
+"的边也被删除!
";
AfxMessageBox(str);
size--;
i--;
CEdge*CGraph:
GetOneEdgeBy2Nodes(CNode*sideNode1,CNode*sideNode2)
ASSERT(sideNode1!
=NULL);
ASSERT(sideNode2!
for(inti=0;i{if(this->m_edgeArray.GetAt(i).m_nodeIndex1==sideNode1->m_nodeIndex){if(m_edgeArray.GetAt(i).m_nodeIndex2==sideNode2->m_nodeIndex)return&this->m_edgeArray[i];}elseif(this->m_edgeArray.GetAt(i).m_nodeIndex1==sideNode2->m_nodeIndex){if(m_edgeArray.GetAt(i).m_nodeIndex2==sideNode1->m_nodeIndex)return&this->m_edgeArray[i];}elsecontinue;}returnNULL;}//由索引值得到一个结点的地址,如果没有就返回NULL。CNode*CGraph::GetOneNodeByIndex(intindex){intsize=this->m_nodeArray.GetSize();for(inti=0;i{if(this->m_nodeArray.GetAt(i).m_nodeIndex==index){return&m_nodeArray[i];}}returnNULL;}/////////////////////////////////////////////////////////////////////////////////////////////生成导游图!//////////////////////////////////////////////////////////////////////////////////////////////[参数]:nIndexStart入口结点索引值//nIndexEnd出品结点索引值,0代表任意的//入口或出口结点都可做为出口////[返回]:生成成功返回true,否则返回false;////[数据结构要求]://能够从一个结点得到它的所有的有边相连的其它结点,在这里使用邻接表.//用树来表示所有可能的路线方案集合////ALGraph:表示用邻接表表示成的图//AdList:typedefCListAdList;//邻接表中的一条链表,表头表示图中一个顶点,链表中的其它//元素表示它们与该顶点之间的边关系//EdgeNode:邻接表中的一个元素,表示从一个结点到它相邻的结点及其边////Tree:用来描述一棵树,代表其中的一个结点//dequeactiveNode:用来记录在生成这棵树的过程中,当前有哪些结点正//在等待生成子结点。一旦它生成了它的子结点(与它//相邻的那些结点),它就变成了一个父结点,也将从//activeNode队列中删除,并将它生成的那些子结点再//加入activeNode队列当中去。///*[关于树结构的问题]:如果使用在栈上生成Tree的话,就会造成一出Tree的作用域,将自动析构。因此这里采用new的方法在堆上生成树结点。为了解决内存释放,在这里将每次new出来的Tree*的地址保存起来,这样在最后只要将保存在数组里面的Tree给全部释放掉即可。*/boolCGraph::CreateGuideMap(intnIndexStart,intnIndexEnd){CWaitCursormake_a_wait_cursor_during_this_function;//创建邻接表ALGraphg;this->CreateAdjacencyListGraph(g);if(this->IsConnectedGraph(g)==false)//连通图{AfxMessageBox("该图不是一个连通图\n路径配置出错\n请联系管理员");theApp.SetCurrentStatus(Normal);returnfalse;}/*//开始创建搜索树!Tree*root=newTree;allTreeItemPtrArray.push_back(root);root->nPathLength=0;root->pNode=this->GetOneNodeByIndex(nIndexStart);root->pParent=NULL;root->pEdge=NULL;activeNodeDeque.push_back(root);*/dequeactiveNodeDeque;//队列用来记录还未扩展的结点//theApp.SetCurrentStatus(Normal);vectorbestGuideMap;//保存搜索到的最优路径!vector>bestGuideMaps;//保存所有的最优路径!doublebestLength=-1;//初使化最短路径长度为-1vectorallTreeItemPtrArray;//用一个数组来记录所有new出来的Tree,以便于释放//开始创建搜索树!Tree*root=newTree;allTreeItemPtrArray.push_back(root);root->nPathLength=0;root->pNode=this->GetOneNodeByIndex(nIndexStart);root->pParent=NULL;root->pEdge=NULL;activeNodeDeque.push_back(root);while(activeNodeDeque.size()!=0){//取出队列中的头一个结点,作为父结点Tree*parentNode=activeNodeDeque[0];//从邻接表中得到该结点的边,生成子结点intindex=g.GetNodeIndex(parentNode->pNode);ASSERT(index!=-1);//链表中第一个结点为本身,后面的为与其相邻接的边POSITIONpos=g.pList[index].GetHeadPosition();g.pList[index].GetNext(pos);//第一个结点不是边while(pos!=NULL){//在邻接表中获取下一个相邻结点,在树中生成子结点EdgeNodeen=g.pList[index].GetNext(pos);//[裁枝]:如果这条新路径的长度已经大于最短路径,忽略if(bestLength!=-1&&(parentNode->nPathLength+en.pEdge->m_pathLength)>bestLength)continue;//[裁枝]:如果再走了一回重复的路(如1-2-1-2,不考虑1-2-3-2-1-2-3,或更多重复)Tree*gradeParentTree=parentNode->pParent;if(gradeParentTree!=NULL){if(en.pNode==gradeParentTree->pNode){Tree*gradeGradeParentTree=gradeParentTree->pParent;if(gradeGradeParentTree!=NULL){if(parentNode->pNode==gradeGradeParentTree->pNode)continue;}}}//创建一个新的树结点Tree*pTreeNode=newTree;if(pTreeNode==NULL){AfxMessageBox("创建对象失败,堆内存不足...");gotoEND;}allTreeItemPtrArray.push_back(pTreeNode);pTreeNode->nPathLength=parentNode->nPathLength+en.pEdge->m_pathLength;pTreeNode->pNode=en.pNode;pTreeNode->pParent=parentNode;pTreeNode->pEdge=en.pEdge;TRACE2("生成<%s>的子树<%s>\n",parentNode->pNode->m_nodeName,pTreeNode->pNode->m_nodeName);//加入活动结点activeNodeDeque.push_back(pTreeNode);TRACE1("入队:<%s>\n",pTreeNode->pNode->m_nodeName);//出口判断if(endPointTest(pTreeNode,nIndexEnd)){TRACE0("找到一条向导路径!下一步该进行裁枝了!\n");boolneed=false;//是否需要重新裁枝bestGuideMap.clear();if(pTreeNode->nPathLength{need=true;//找到一条最优路径bestLength=pTreeNode->nPathLength;bestGuideMaps.clear();Tree*pTemp=pTreeNode;while(pTemp!=NULL){bestGuideMap.push_back(pTemp);pTemp=pTemp->pParent;}bestGuideMaps.push_back(bestGuideMap);}elseif(pTreeNode->nPathLength==bestLength){//找到一另外一条最短路径Tree*pTemp=pTreeNode;while(pTemp!=NULL){bestGuideMap.push_back(pTemp);pTemp=pTemp->pParent;}bestGuideMaps.push_back(bestGuideMap);}else{activeNodeDeque.pop_back();//刚放队列的这条路径不会是最优路径,删除continue;}//关于怎么裁枝:<将其它路径长度已经大于最优路径的长度的子树删除>//只要将活动结点队列中大于最优长度的结点从活动结点队列中删除就行了//因为当活动结点队列为空,整个搜索过程就结束了//删除时不去查看队列中的第一个,因为正在处理它,从第二个开始算起if(need==false)//不需要再裁枝continue;if(activeNodeDeque.size()<2)continue;std::deque::iteratoriter=activeNodeDeque.begin();std::deque::iteratoriterEnd=activeNodeDeque.end();iter++;for(;iter!=iterEnd;iter++){if((*iter)->nPathLength>pTreeNode->nPathLength)//删除掉这个活动结点{ASSERT((*iter)->nPathLength!=0);TRACE1("删除一个活动结点:\t%f\n",(*iter)->nPathLength);activeNodeDeque.erase(iter);//iter,iterEnd被破坏了...重新获取iter=activeNodeDeque.begin();iter++;iterEnd=activeNodeDeque.end();}}}}//父结点处理完毕,从活动结点删除activeNodeDeque.pop_front();}END://输出最优路径CPathDlgdlg((DWORD)&bestGuideMaps,(DWORD)this);dlg.DoModal();//内存释放//释放剩余资源intptrCount=allTreeItemPtrArray.size();for(intj=0;j{deleteallTreeItemPtrArray[j];}allTreeItemPtrArray.clear();//退出向导模式theApp.SetCurrentStatus(Normal);returntrue;}//在这里用来生成邻接链表!voidCGraph::CreateAdjacencyListGraph(ALGraph&g){//1,纵向添加头结点intsize=this->m_nodeArray.GetSize();g.pList=newAdList[size];g.nNodeCount=size;for(inti=0;i{EdgeNodeen;en.pNode=&this->m_nodeArray[i];//保存地址,用地址来存储g.pList[i].AddHead(en);}//2,横向添加边intedgeSize=this->m_edgeArray.GetSize();for(intj=0;j{CNode*sideNode1=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex1);CNode*sideNode2=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex2);//两个端点分别添加一次for(intk=0;kif(g.pList[k].GetHead().pNode==sideNode1){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode2;g.pList[k].AddTail(node);break;}for(intl=0;lif(g.pList[l].GetHead().pNode==sideNode2){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode1;g.pList[l].AddTail(node);break;}}}/***************************************************************
if(this->m_edgeArray.GetAt(i).m_nodeIndex1==sideNode1->m_nodeIndex)
if(m_edgeArray.GetAt(i).m_nodeIndex2==sideNode2->m_nodeIndex)
return&this->m_edgeArray[i];
elseif(this->m_edgeArray.GetAt(i).m_nodeIndex1==sideNode2->m_nodeIndex)
if(m_edgeArray.GetAt(i).m_nodeIndex2==sideNode1->m_nodeIndex)
else
continue;
returnNULL;
//由索引值得到一个结点的地址,如果没有就返回NULL。
CNode*CGraph:
GetOneNodeByIndex(intindex)
for(inti=0;i{if(this->m_nodeArray.GetAt(i).m_nodeIndex==index){return&m_nodeArray[i];}}returnNULL;}/////////////////////////////////////////////////////////////////////////////////////////////生成导游图!//////////////////////////////////////////////////////////////////////////////////////////////[参数]:nIndexStart入口结点索引值//nIndexEnd出品结点索引值,0代表任意的//入口或出口结点都可做为出口////[返回]:生成成功返回true,否则返回false;////[数据结构要求]://能够从一个结点得到它的所有的有边相连的其它结点,在这里使用邻接表.//用树来表示所有可能的路线方案集合////ALGraph:表示用邻接表表示成的图//AdList:typedefCListAdList;//邻接表中的一条链表,表头表示图中一个顶点,链表中的其它//元素表示它们与该顶点之间的边关系//EdgeNode:邻接表中的一个元素,表示从一个结点到它相邻的结点及其边////Tree:用来描述一棵树,代表其中的一个结点//dequeactiveNode:用来记录在生成这棵树的过程中,当前有哪些结点正//在等待生成子结点。一旦它生成了它的子结点(与它//相邻的那些结点),它就变成了一个父结点,也将从//activeNode队列中删除,并将它生成的那些子结点再//加入activeNode队列当中去。///*[关于树结构的问题]:如果使用在栈上生成Tree的话,就会造成一出Tree的作用域,将自动析构。因此这里采用new的方法在堆上生成树结点。为了解决内存释放,在这里将每次new出来的Tree*的地址保存起来,这样在最后只要将保存在数组里面的Tree给全部释放掉即可。*/boolCGraph::CreateGuideMap(intnIndexStart,intnIndexEnd){CWaitCursormake_a_wait_cursor_during_this_function;//创建邻接表ALGraphg;this->CreateAdjacencyListGraph(g);if(this->IsConnectedGraph(g)==false)//连通图{AfxMessageBox("该图不是一个连通图\n路径配置出错\n请联系管理员");theApp.SetCurrentStatus(Normal);returnfalse;}/*//开始创建搜索树!Tree*root=newTree;allTreeItemPtrArray.push_back(root);root->nPathLength=0;root->pNode=this->GetOneNodeByIndex(nIndexStart);root->pParent=NULL;root->pEdge=NULL;activeNodeDeque.push_back(root);*/dequeactiveNodeDeque;//队列用来记录还未扩展的结点//theApp.SetCurrentStatus(Normal);vectorbestGuideMap;//保存搜索到的最优路径!vector>bestGuideMaps;//保存所有的最优路径!doublebestLength=-1;//初使化最短路径长度为-1vectorallTreeItemPtrArray;//用一个数组来记录所有new出来的Tree,以便于释放//开始创建搜索树!Tree*root=newTree;allTreeItemPtrArray.push_back(root);root->nPathLength=0;root->pNode=this->GetOneNodeByIndex(nIndexStart);root->pParent=NULL;root->pEdge=NULL;activeNodeDeque.push_back(root);while(activeNodeDeque.size()!=0){//取出队列中的头一个结点,作为父结点Tree*parentNode=activeNodeDeque[0];//从邻接表中得到该结点的边,生成子结点intindex=g.GetNodeIndex(parentNode->pNode);ASSERT(index!=-1);//链表中第一个结点为本身,后面的为与其相邻接的边POSITIONpos=g.pList[index].GetHeadPosition();g.pList[index].GetNext(pos);//第一个结点不是边while(pos!=NULL){//在邻接表中获取下一个相邻结点,在树中生成子结点EdgeNodeen=g.pList[index].GetNext(pos);//[裁枝]:如果这条新路径的长度已经大于最短路径,忽略if(bestLength!=-1&&(parentNode->nPathLength+en.pEdge->m_pathLength)>bestLength)continue;//[裁枝]:如果再走了一回重复的路(如1-2-1-2,不考虑1-2-3-2-1-2-3,或更多重复)Tree*gradeParentTree=parentNode->pParent;if(gradeParentTree!=NULL){if(en.pNode==gradeParentTree->pNode){Tree*gradeGradeParentTree=gradeParentTree->pParent;if(gradeGradeParentTree!=NULL){if(parentNode->pNode==gradeGradeParentTree->pNode)continue;}}}//创建一个新的树结点Tree*pTreeNode=newTree;if(pTreeNode==NULL){AfxMessageBox("创建对象失败,堆内存不足...");gotoEND;}allTreeItemPtrArray.push_back(pTreeNode);pTreeNode->nPathLength=parentNode->nPathLength+en.pEdge->m_pathLength;pTreeNode->pNode=en.pNode;pTreeNode->pParent=parentNode;pTreeNode->pEdge=en.pEdge;TRACE2("生成<%s>的子树<%s>\n",parentNode->pNode->m_nodeName,pTreeNode->pNode->m_nodeName);//加入活动结点activeNodeDeque.push_back(pTreeNode);TRACE1("入队:<%s>\n",pTreeNode->pNode->m_nodeName);//出口判断if(endPointTest(pTreeNode,nIndexEnd)){TRACE0("找到一条向导路径!下一步该进行裁枝了!\n");boolneed=false;//是否需要重新裁枝bestGuideMap.clear();if(pTreeNode->nPathLength{need=true;//找到一条最优路径bestLength=pTreeNode->nPathLength;bestGuideMaps.clear();Tree*pTemp=pTreeNode;while(pTemp!=NULL){bestGuideMap.push_back(pTemp);pTemp=pTemp->pParent;}bestGuideMaps.push_back(bestGuideMap);}elseif(pTreeNode->nPathLength==bestLength){//找到一另外一条最短路径Tree*pTemp=pTreeNode;while(pTemp!=NULL){bestGuideMap.push_back(pTemp);pTemp=pTemp->pParent;}bestGuideMaps.push_back(bestGuideMap);}else{activeNodeDeque.pop_back();//刚放队列的这条路径不会是最优路径,删除continue;}//关于怎么裁枝:<将其它路径长度已经大于最优路径的长度的子树删除>//只要将活动结点队列中大于最优长度的结点从活动结点队列中删除就行了//因为当活动结点队列为空,整个搜索过程就结束了//删除时不去查看队列中的第一个,因为正在处理它,从第二个开始算起if(need==false)//不需要再裁枝continue;if(activeNodeDeque.size()<2)continue;std::deque::iteratoriter=activeNodeDeque.begin();std::deque::iteratoriterEnd=activeNodeDeque.end();iter++;for(;iter!=iterEnd;iter++){if((*iter)->nPathLength>pTreeNode->nPathLength)//删除掉这个活动结点{ASSERT((*iter)->nPathLength!=0);TRACE1("删除一个活动结点:\t%f\n",(*iter)->nPathLength);activeNodeDeque.erase(iter);//iter,iterEnd被破坏了...重新获取iter=activeNodeDeque.begin();iter++;iterEnd=activeNodeDeque.end();}}}}//父结点处理完毕,从活动结点删除activeNodeDeque.pop_front();}END://输出最优路径CPathDlgdlg((DWORD)&bestGuideMaps,(DWORD)this);dlg.DoModal();//内存释放//释放剩余资源intptrCount=allTreeItemPtrArray.size();for(intj=0;j{deleteallTreeItemPtrArray[j];}allTreeItemPtrArray.clear();//退出向导模式theApp.SetCurrentStatus(Normal);returntrue;}//在这里用来生成邻接链表!voidCGraph::CreateAdjacencyListGraph(ALGraph&g){//1,纵向添加头结点intsize=this->m_nodeArray.GetSize();g.pList=newAdList[size];g.nNodeCount=size;for(inti=0;i{EdgeNodeen;en.pNode=&this->m_nodeArray[i];//保存地址,用地址来存储g.pList[i].AddHead(en);}//2,横向添加边intedgeSize=this->m_edgeArray.GetSize();for(intj=0;j{CNode*sideNode1=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex1);CNode*sideNode2=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex2);//两个端点分别添加一次for(intk=0;kif(g.pList[k].GetHead().pNode==sideNode1){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode2;g.pList[k].AddTail(node);break;}for(intl=0;lif(g.pList[l].GetHead().pNode==sideNode2){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode1;g.pList[l].AddTail(node);break;}}}/***************************************************************
if(this->m_nodeArray.GetAt(i).m_nodeIndex==index)
return&m_nodeArray[i];
///////////////////////////////////////////////////////////////////////////////////////////
//生成导游图!
//////////////////////////////////////////////////////////////////////////////////////////
//[参数]:
nIndexStart入口结点索引值
//nIndexEnd出品结点索引值,0代表任意的
//入口或出口结点都可做为出口
//[返回]:
生成成功返回true,否则返回false;
//[数据结构要求]:
//能够从一个结点得到它的所有的有边相连的其它结点,在这里使用邻接表.
//用树来表示所有可能的路线方案集合
//ALGraph:
表示用邻接表表示成的图
//AdList:
typedefCListAdList;
//邻接表中的一条链表,表头表示图中一个顶点,链表中的其它
//元素表示它们与该顶点之间的边关系
//EdgeNode:
邻接表中的一个元素,表示从一个结点到它相邻的结点及其边
//Tree:
用来描述一棵树,代表其中的一个结点
//dequeactiveNode:
用来记录在生成这棵树的过程中,当前有哪些结点正
//在等待生成子结点。
一旦它生成了它的子结点(与它
//相邻的那些结点),它就变成了一个父结点,也将从
//activeNode队列中删除,并将它生成的那些子结点再
//加入activeNode队列当中去。
/*
[关于树结构的问题]:
如果使用在栈上生成Tree的话,就会造成一出Tree的作用域,将自动析构。
因此这里采用new的方法在堆上生成树结点。
为了解决内存释放,在这里将每次new出来的Tree*
的地址保存起来,这样在最后只要将保存在数组里面的Tree给全部释放掉即可。
*/
boolCGraph:
CreateGuideMap(intnIndexStart,intnIndexEnd)
CWaitCursormake_a_wait_cursor_during_this_function;
//创建邻接表
ALGraphg;
this->CreateAdjacencyListGraph(g);
if(this->IsConnectedGraph(g)==false)//连通图
AfxMessageBox("该图不是一个连通图\n路径配置出错\n请联系管理员");
theApp.SetCurrentStatus(Normal);
returnfalse;
//开始创建搜索树!
Tree*root=newTree;
allTreeItemPtrArray.push_back(root);
root->nPathLength=0;
root->pNode=this->GetOneNodeByIndex(nIndexStart);
root->pParent=NULL;
root->pEdge=NULL;
activeNodeDeque.push_back(root);
dequeactiveNodeDeque;//队列用来记录还未扩展的结点
//theApp.SetCurrentStatus(Normal);
vectorbestGuideMap;//保存搜索到的最优路径!
vector>bestGuideMaps;//保存所有的最优路径!
doublebestLength=-1;//初使化最短路径长度为-1
vectorallTreeItemPtrArray;//用一个数组来记录所有new出来的Tree,以便于释放
while(activeNodeDeque.size()!
=0)
//取出队列中的头一个结点,作为父结点
Tree*parentNode=activeNodeDeque[0];
//从邻接表中得到该结点的边,生成子结点
intindex=g.GetNodeIndex(parentNode->pNode);
ASSERT(index!
=-1);
//链表中第一个结点为本身,后面的为与其相邻接的边
POSITIONpos=g.pList[index].GetHeadPosition();
g.pList[index].GetNext(pos);//第一个结点不是边
while(pos!
=NULL)
//在邻接表中获取下一个相邻结点,在树中生成子结点
EdgeNodeen=g.pList[index].GetNext(pos);
//[裁枝]:
如果这条新路径的长度已经大于最短路径,忽略
if(bestLength!
=-1&&
(parentNode->nPathLength+en.pEdge->m_pathLength)>bestLength
)
//[裁枝]:
如果再走了一回重复的路(如1-2-1-2,不考虑1-2-3-2-1-2-3,或更多重复)
Tree*gradeParentTree=parentNode->pParent;
if(gradeParentTree!
if(en.pNode==gradeParentTree->pNode)
Tree*gradeGradeParentTree=gradeParentTree->pParent;
if(gradeGradeParentTree!
if(parentNode->pNode==gradeGradeParentTree->pNode)
//创建一个新的树结点
Tree*pTreeNode=newTree;
if(pTreeNode==NULL)
AfxMessageBox("创建对象失败,堆内存不足...");
gotoEND;
allTreeItemPtrArray.push_back(pTreeNode);
pTreeNode->nPathLength=parentNode->nPathLength+en.pEdge->m_pathLength;
pTreeNode->pNode=en.pNode;
pTreeNode->pParent=parentNode;
pTreeNode->pEdge=en.pEdge;
TRACE2("生成<%s>的子树<%s>\n",parentNode->pNode->m_nodeName,pTreeNode->pNode->m_nodeName);
//加入活动结点
activeNodeDeque.push_back(pTreeNode);
TRACE1("入队:
<%s>\n",pTreeNode->pNode->m_nodeName);
//出口判断
if(endPointTest(pTreeNode,nIndexEnd))
TRACE0("找到一条向导路径!
下一步该进行裁枝了!
\n");
boolneed=false;//是否需要重新裁枝
bestGuideMap.clear();
if(pTreeNode->nPathLength{need=true;//找到一条最优路径bestLength=pTreeNode->nPathLength;bestGuideMaps.clear();Tree*pTemp=pTreeNode;while(pTemp!=NULL){bestGuideMap.push_back(pTemp);pTemp=pTemp->pParent;}bestGuideMaps.push_back(bestGuideMap);}elseif(pTreeNode->nPathLength==bestLength){//找到一另外一条最短路径Tree*pTemp=pTreeNode;while(pTemp!=NULL){bestGuideMap.push_back(pTemp);pTemp=pTemp->pParent;}bestGuideMaps.push_back(bestGuideMap);}else{activeNodeDeque.pop_back();//刚放队列的这条路径不会是最优路径,删除continue;}//关于怎么裁枝:<将其它路径长度已经大于最优路径的长度的子树删除>//只要将活动结点队列中大于最优长度的结点从活动结点队列中删除就行了//因为当活动结点队列为空,整个搜索过程就结束了//删除时不去查看队列中的第一个,因为正在处理它,从第二个开始算起if(need==false)//不需要再裁枝continue;if(activeNodeDeque.size()<2)continue;std::deque::iteratoriter=activeNodeDeque.begin();std::deque::iteratoriterEnd=activeNodeDeque.end();iter++;for(;iter!=iterEnd;iter++){if((*iter)->nPathLength>pTreeNode->nPathLength)//删除掉这个活动结点{ASSERT((*iter)->nPathLength!=0);TRACE1("删除一个活动结点:\t%f\n",(*iter)->nPathLength);activeNodeDeque.erase(iter);//iter,iterEnd被破坏了...重新获取iter=activeNodeDeque.begin();iter++;iterEnd=activeNodeDeque.end();}}}}//父结点处理完毕,从活动结点删除activeNodeDeque.pop_front();}END://输出最优路径CPathDlgdlg((DWORD)&bestGuideMaps,(DWORD)this);dlg.DoModal();//内存释放//释放剩余资源intptrCount=allTreeItemPtrArray.size();for(intj=0;j{deleteallTreeItemPtrArray[j];}allTreeItemPtrArray.clear();//退出向导模式theApp.SetCurrentStatus(Normal);returntrue;}//在这里用来生成邻接链表!voidCGraph::CreateAdjacencyListGraph(ALGraph&g){//1,纵向添加头结点intsize=this->m_nodeArray.GetSize();g.pList=newAdList[size];g.nNodeCount=size;for(inti=0;i{EdgeNodeen;en.pNode=&this->m_nodeArray[i];//保存地址,用地址来存储g.pList[i].AddHead(en);}//2,横向添加边intedgeSize=this->m_edgeArray.GetSize();for(intj=0;j{CNode*sideNode1=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex1);CNode*sideNode2=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex2);//两个端点分别添加一次for(intk=0;kif(g.pList[k].GetHead().pNode==sideNode1){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode2;g.pList[k].AddTail(node);break;}for(intl=0;lif(g.pList[l].GetHead().pNode==sideNode2){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode1;g.pList[l].AddTail(node);break;}}}/***************************************************************
need=true;
//找到一条最优路径
bestLength=pTreeNode->nPathLength;
bestGuideMaps.clear();
Tree*pTemp=pTreeNode;
while(pTemp!
bestGuideMap.push_back(pTemp);
pTemp=pTemp->pParent;
bestGuideMaps.push_back(bestGuideMap);
elseif(pTreeNode->nPathLength==bestLength)
//找到一另外一条最短路径
activeNodeDeque.pop_back();//刚放队列的这条路径不会是最优路径,删除
//关于怎么裁枝:
<将其它路径长度已经大于最优路径的长度的子树删除>
//只要将活动结点队列中大于最优长度的结点从活动结点队列中删除就行了
//因为当活动结点队列为空,整个搜索过程就结束了
//删除时不去查看队列中的第一个,因为正在处理它,从第二个开始算起
if(need==false)//不需要再裁枝
if(activeNodeDeque.size()<2)
std:
deque:
iteratoriter=activeNodeDeque.begin();
iteratoriterEnd=activeNodeDeque.end();
iter++;
for(;iter!
=iterEnd;iter++)
if((*iter)->nPathLength>pTreeNode->nPathLength)//删除掉这个活动结点
ASSERT((*iter)->nPathLength!
=0);
TRACE1("删除一个活动结点:
\t%f\n",(*iter)->nPathLength);
activeNodeDeque.erase(iter);//iter,iterEnd被破坏了...重新获取
iter=activeNodeDeque.begin();
iterEnd=activeNodeDeque.end();
//父结点处理完毕,从活动结点删除
activeNodeDeque.pop_front();
END:
//输出最优路径
CPathDlgdlg((DWORD)&bestGuideMaps,(DWORD)this);
dlg.DoModal();
//内存释放//释放剩余资源
intptrCount=allTreeItemPtrArray.size();
for(intj=0;j{deleteallTreeItemPtrArray[j];}allTreeItemPtrArray.clear();//退出向导模式theApp.SetCurrentStatus(Normal);returntrue;}//在这里用来生成邻接链表!voidCGraph::CreateAdjacencyListGraph(ALGraph&g){//1,纵向添加头结点intsize=this->m_nodeArray.GetSize();g.pList=newAdList[size];g.nNodeCount=size;for(inti=0;i{EdgeNodeen;en.pNode=&this->m_nodeArray[i];//保存地址,用地址来存储g.pList[i].AddHead(en);}//2,横向添加边intedgeSize=this->m_edgeArray.GetSize();for(intj=0;j{CNode*sideNode1=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex1);CNode*sideNode2=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex2);//两个端点分别添加一次for(intk=0;kif(g.pList[k].GetHead().pNode==sideNode1){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode2;g.pList[k].AddTail(node);break;}for(intl=0;lif(g.pList[l].GetHead().pNode==sideNode2){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode1;g.pList[l].AddTail(node);break;}}}/***************************************************************
deleteallTreeItemPtrArray[j];
allTreeItemPtrArray.clear();
//退出向导模式
returntrue;
//在这里用来生成邻接链表!
CreateAdjacencyListGraph(ALGraph&g)
//1,纵向添加头结点
g.pList=newAdList[size];
g.nNodeCount=size;
for(inti=0;i{EdgeNodeen;en.pNode=&this->m_nodeArray[i];//保存地址,用地址来存储g.pList[i].AddHead(en);}//2,横向添加边intedgeSize=this->m_edgeArray.GetSize();for(intj=0;j{CNode*sideNode1=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex1);CNode*sideNode2=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex2);//两个端点分别添加一次for(intk=0;kif(g.pList[k].GetHead().pNode==sideNode1){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode2;g.pList[k].AddTail(node);break;}for(intl=0;lif(g.pList[l].GetHead().pNode==sideNode2){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode1;g.pList[l].AddTail(node);break;}}}/***************************************************************
EdgeNodeen;
en.pNode=&this->m_nodeArray[i];//保存地址,用地址来存储
g.pList[i].AddHead(en);
//2,横向添加边
intedgeSize=this->m_edgeArray.GetSize();
for(intj=0;j{CNode*sideNode1=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex1);CNode*sideNode2=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex2);//两个端点分别添加一次for(intk=0;kif(g.pList[k].GetHead().pNode==sideNode1){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode2;g.pList[k].AddTail(node);break;}for(intl=0;lif(g.pList[l].GetHead().pNode==sideNode2){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode1;g.pList[l].AddTail(node);break;}}}/***************************************************************
CNode*sideNode1=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex1);
CNode*sideNode2=this->GetOneNodeByIndex(this->m_edgeArray[j].m_nodeIndex2);
//两个端点分别添加一次
for(intk=0;kif(g.pList[k].GetHead().pNode==sideNode1){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode2;g.pList[k].AddTail(node);break;}for(intl=0;lif(g.pList[l].GetHead().pNode==sideNode2){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode1;g.pList[l].AddTail(node);break;}}}/***************************************************************
if(g.pList[k].GetHead().pNode==sideNode1)
EdgeNodenode;
node.pEdge=&m_edgeArray[j];
node.pNode=sideNode2;
g.pList[k].AddTail(node);
for(intl=0;lif(g.pList[l].GetHead().pNode==sideNode2){EdgeNodenode;node.pEdge=&m_edgeArray[j];node.pNode=sideNode1;g.pList[l].AddTail(node);break;}}}/***************************************************************
if(g.pList[l].GetHead().pNode==sideNode2)
node.pNode=sideNode1;
g.pList[l].AddTail(node);
/***************************************************************
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1