数据结构——图的深度遍历

简介:

图的遍历方式有两种,

  1. 深度优先
  2. 广度优先

深度优先采用的是递归的方式来来实现,思想如下:

假设给定图G的初态是所有顶点均未曾访问过。在G中任选一顶点v为初始出发点(源点),
**则深度优先遍历可定义如下:
首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。**
流程图如下:
因为采用的是递归调用,那就需要有两个函数,主要的递归调用的函数是放在private中的;在public有一个函数来调用这个递归函数,
public函数流程图如下:
image
private 函数如下:
image

在这里用的临界表的形式来存储无向图;
图的结构体的定义和我图的十字链表表示法中图的结构体定义差不多,只是增加了一个标记位。用来标记这个结点是不是被访问过。图示如下:
还是要定义两个结构体,图的邻接表是采用数组+链表的方式来实现的。那链表的结构体定义如下:
image
数组的结构体定义如下:
image

在这里是用无向图图的实现的,其实有向图的实现和这个差不多少,还是也可以采用图的邻接表来实现,其实基本一样,大体是一样的,还是要设置标记位。我是采用下面的图的测试的。

image
代码如下:

//  GraphList.cpp
//  深度优先遍历
//
//  Created by 橘子和香蕉 on 2018/11/25.
//  Copyright © 2018 橘子和香蕉. All rights reserved.
//


/*
 遇到的问题:
 1:首先是添加边;用户输入的两个结点,先要判断哪个结点是新添加的,是俩都是,还是一个是,,然后设置位置。添加结点先是将数据放在数组,然后要将它添加到相应的链表中去,那就要申请新结点,我就是在初始化结点的时候没有将结点中指针设置为NULL,才导致了我之后的错误,想想就觉得自己蠢。
2:在删除结点的时候要判断这个结点还有没有邻结点,若是没有,就要删除这个结点,
 */

#include <iostream>
using namespace std;
#define dataType char
#define MAXSIZE 100
typedef struct  node{
    int position;
    node *next;
}node;
typedef struct Box{
    dataType data;
    node *out;
    bool isAccess;
}Box;
class Graph{
private:
    Box base[MAXSIZE];
    int vertexNum;
    int edgeNum;
    int  locate(dataType data);
    
    void deleteEdgePrivate(int  startPosition,int endPositon);
    void def(int position);
    bool isNotHaveNevNode(dataType data);
    void moveNode(dataType data);
    
public:
    ~Graph();
    void init(int vertexNum,int edgeNum);
    void create();
    void printNode(dataType data);
    void printGraph();
    void addEdge(dataType start,dataType end);
    void deleteEdge(dataType start,dataType end);
    void depthErgodic(dataType data);
    
};
Graph::~Graph(){
    for (int i = 0; i<vertexNum; i++) {
        node  *p= base[i].out;
        node *h = p;
        while ( p != NULL) {
            
            h = p->next;
            if(h == NULL) return;
            delete p;
            p = h->next;
        }
    }
    //    delete []base;
}
void Graph::init(int vertexNum, int edgeNum){
    this->vertexNum = vertexNum;
    this->edgeNum = edgeNum;
}
int  Graph::locate(dataType data){
    for (int i = 0; i<vertexNum; i++) {
        if(base[i].data == data){
            return i;
        }
    }
    return -1;
}
void Graph::create(){
    cout<<"create Graph begin\n";
    for (int i = 0; i<vertexNum; i++) {
        cout<<"input node data\n";
        cin>>base[i].data;
        base[i].out = NULL;
        base[i].isAccess = false;
    }
    node *startNode,*endNode;
    int startPosition;
    int endPosition;
    dataType start;
    dataType end;
    for (int i = 0; i<edgeNum; i++) {
        cout<<"input edge start and end\n";
        cin>>start>>end;
        startPosition = locate(start);
        endPosition = locate(end);
        //创建链表。先是创建start指向end;
        //在创建end指向start;
        endNode = new node;
        endNode->position = endPosition;
        endNode->next =  base[startPosition].out;
        base[startPosition].out = endNode;
        
        startNode = new node;
        startNode->position = startPosition;
        startNode->next = base[endPosition].out;
        base[endPosition].out = startNode;
    }
    
    
}
void Graph::printNode(dataType data){
    int position = locate(data);
    if(position == -1){
        cout<<"data is not exist\n";
        return;
    }
    else{
        node *h = base[position].out;
        cout<<"the data of"<<data<<":\t";
        while (h!=NULL) {
            cout<<base[h->position].data<<"\t";
            h=h->next;
        }
    }
    cout<<"\n";
}
void Graph::printGraph(){
    for (int i = 0; i<vertexNum; i++) {
        printNode(base[i].data);
    }
}
void Graph::addEdge(dataType start, dataType end){
    
    int startPosition = locate(start);
    int endPosition = locate(end);
    if(startPosition == -1){
        base[vertexNum].data = start;
        base[vertexNum].out = NULL;
        startPosition = vertexNum;
        init(vertexNum +1 , edgeNum+1);
    }
    if(endPosition == -1){
        base[vertexNum].data = end;
        base[vertexNum].out = NULL;
        endPosition = vertexNum;
        init(vertexNum +1 , edgeNum+1);
    }
    if(startPosition == -1 && endPosition == -1){
        
        base[vertexNum].data = start;
        startPosition = vertexNum;
        init(vertexNum +1 , edgeNum+1);
        
        base[vertexNum].data = end;
        endPosition = vertexNum;
        init(vertexNum +1 , edgeNum+1);
    }
    node* endNode = new node;
    endNode->position = endPosition;
    endNode->next = base[startPosition].out;
    base[startPosition].out = endNode;
    
    node* startNode = new node;
    startNode->position = startPosition;
    startNode->next = base[endPosition].out;
    base[endPosition].out = startNode;
    
    
}


void Graph::deleteEdge(dataType start, dataType end){
    
    /*
     a:删除的时候要判断俩结点的位置,然后一个一个的删除,先是删除start 到end这条表
        然后接着删除end到start这条边;
        其实删除的操作都是一样的,然后我就将删除的操作独立了出来,写了一个函数,放到private中去,
        删除start 到end和删除end到start只不过就是在函数调用的时候颠倒就好了,但是这只限于无向图。
     */
    int startPosition= locate(start);
    int endPositon = locate(end);
    if(startPosition ==-1 || endPositon == -1){
        cout<<"node is not exist\n";
        return;
    }
    deleteEdgePrivate( startPosition,endPositon);
    deleteEdgePrivate(endPositon, startPosition);
    if( isNotHaveNevNode(start) == true){
        moveNode(start);
    }
    if(isNotHaveNevNode(end) == true){
        moveNode(end);
    }
}


void Graph::deleteEdgePrivate(int  startPosition,int endPositon){
    int n = 0;
    node * p = base[startPosition].out;
    node *h = base[startPosition].out;
    
    
    while (p != NULL) {
        
        if(n ==0 && p->position == endPositon ) {
            base[startPosition].out = p->next;
            delete p;
            return;
        }
        n++;
        if(n != 0 && p->position == endPositon){
            h->next = p->next;
            cout<<"  "<<base[p->position].data<<endl;
            delete p;
            return ;
        }
        h = p;
        p = p->next;
    }
}

void Graph::depthErgodic(dataType data){
    int position = locate(data);
    position == -1?cout<<"the data is not exist\n":cout<<"";
    def(position);
    
}
void Graph::def(int position){
    node *p;
    cout<<base[position].data<<endl;
    base[position].isAccess = true;
    p = base[position].out;
    
    while (p != NULL) {
        if(base[p->position].isAccess == false){
            def(p->position);
        }
        p = p->next;
    }
}
/*p
 判断还有没有邻结点
 */
bool Graph::isNotHaveNevNode(dataType data){
    int position = locate(data);
    return  base[position].out == NULL?true:false;
}
/*
 移动数据
 */
void Graph::moveNode(dataType data){
    int position = locate(data);
    for (int i = position; i<vertexNum ; i++) {
        base[i].data = base[i+1].data;
        base[i].out = base[i+1].out;
        base[i].isAccess = base[i+1].isAccess;
    }
    this->vertexNum -= 1;
}
int main(){
    Graph a;
    a.init(4, 4);
    a.create();
//    a.printNode('b');
//    a.printGraph();
    a.addEdge('d', 'e');
    a.printNode('d');
    a.printNode('e');
    a.deleteEdge('d', 'e');
    a.printNode('e');
    return 1;
}

相关文章
|
26天前
|
存储 算法 Go
Golang 数据结构:图
Golang 数据结构:图
45 0
数据结构 | 二叉树的各种遍历
数据结构 | 二叉树的各种遍历
|
3月前
|
存储 算法 Linux
数据结构 | 二叉树的概念及前中后序遍历(一)
数据结构 | 二叉树的概念及前中后序遍历(一)
|
3月前
|
存储 算法 编译器
数据结构之图
数据结构之图
55 0
|
15天前
|
算法
【算法与数据结构】二叉树(前中后)序遍历2
【算法与数据结构】二叉树(前中后)序遍历
|
3月前
|
算法 容器
数据结构与算法之树的遍历
树的 “前” “中” “后” 遍历 //如果要再写一个树太费时间了,所以博主在这篇博客只给出核心代码并赋予GIF演示动画,望大家好好理解以对树的三种遍历方式有更为深刻的理解
42 0
|
3天前
|
存储 机器学习/深度学习 算法
上机实验三 图的最小生成树算法设计 西安石油大学数据结构
上机实验三 图的最小生成树算法设计 西安石油大学数据结构
15 1
|
24天前
|
存储 算法 Serverless
【软件设计师备考 专题 】数据结构深度解析:从数组到图
【软件设计师备考 专题 】数据结构深度解析:从数组到图
56 0
|
1月前
|
存储 算法
数据结构— — 二叉树的遍历
数据结构— — 二叉树的遍历
21 0
|
2月前
|
定位技术 调度
【数据结构入门精讲 | 第十九篇】考研408、企业面试图专项练习(二)
【数据结构入门精讲 | 第十九篇】考研408、企业面试图专项练习(二)
24 0

热门文章

最新文章