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

简介:

图的遍历方式有两种,

  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;
}

相关文章
|
1月前
|
存储 编译器 C++
【初阶数据结构】掌握二叉树遍历技巧与信息求解:深入解析四种遍历方法及树的结构与统计分析
【初阶数据结构】掌握二叉树遍历技巧与信息求解:深入解析四种遍历方法及树的结构与统计分析
|
5月前
|
存储 算法
数据结构===图
数据结构===图
|
1月前
|
存储 算法
数据结构与算法学习十六:树的知识、二叉树、二叉树的遍历(前序、中序、后序、层次)、二叉树的查找(前序、中序、后序、层次)、二叉树的删除
这篇文章主要介绍了树和二叉树的基础知识,包括树的存储方式、二叉树的定义、遍历方法(前序、中序、后序、层次遍历),以及二叉树的查找和删除操作。
27 0
|
2月前
|
存储 算法 C语言
数据结构基础详解(C语言): 二叉树的遍历_线索二叉树_树的存储结构_树与森林详解
本文从二叉树遍历入手,详细介绍了先序、中序和后序遍历方法,并探讨了如何构建二叉树及线索二叉树的概念。接着,文章讲解了树和森林的存储结构,特别是如何将树与森林转换为二叉树形式,以便利用二叉树的遍历方法。最后,讨论了树和森林的遍历算法,包括先根、后根和层次遍历。通过这些内容,读者可以全面了解二叉树及其相关概念。
|
3月前
【数据结构】遍历二叉树(递归思想)-->赋源码
【数据结构】遍历二叉树(递归思想)-->赋源码
53 4
|
4月前
|
算法 Python
逆袭之路!用 Python 玩转图的 DFS 与 BFS,让数据结构难题无处遁形
【7月更文挑战第12天】图的遍历利器:DFS 和 BFS。Python 中,图可表示为邻接表或矩阵。DFS 沿路径深入,回溯时遍历所有可达顶点,适合找路径和环。BFS 层次遍历,先近后远,解决最短路径问题。两者在迷宫、网络路由等场景各显神通。通过练习,掌握这些算法,图处理将游刃有余。
65 3
|
4月前
|
存储 算法 Python
“解锁Python高级数据结构新姿势:图的表示与遍历,让你的算法思维跃升新高度
【7月更文挑战第13天】Python中的图数据结构用于表示复杂关系,通过节点和边连接。常见的表示方法是邻接矩阵(适合稠密图)和邻接表(适合稀疏图)。图遍历包括DFS(深度优先搜索)和BFS(广度优先搜索):DFS深入探索分支,BFS逐层访问邻居。掌握这些技巧对优化算法和解决实际问题至关重要。**
45 1
|
5月前
|
编译器 数据库 索引
数据结构篇:树形数据结构的基本概念及其遍历方法
数据结构篇:树形数据结构的基本概念及其遍历方法
87 0
|
5月前
|
存储 算法
【二叉树】数据结构——BST二叉树基本概念及算法设计(插入、删除、遍历操作)
【二叉树】数据结构——BST二叉树基本概念及算法设计(插入、删除、遍历操作)
|
5月前
|
存储
数据结构学习记录——如何建立图(邻接矩阵、邻接表-图节点的结构、创建并初始化、插入变、完整图的建立)
数据结构学习记录——如何建立图(邻接矩阵、邻接表-图节点的结构、创建并初始化、插入变、完整图的建立)
78 0