JAVA数据结构开坑的第三天(图)

按照学校数据结构实验课安排,第三个实验(第三天)————图。

今天完成的内容:

1.深度搜索(DFS)
2.广度搜索(BFS)
3.最小生成树算法:Prim,Kruskal
4.最短路径:Dijkstra

那么就开始今天实验,实验主要围绕两幅图进行验证,所以可能存在错误。
而且我编写的算法都是作用在邻接矩阵的。
在这里插入图片描述在这里插入图片描述

邻接矩阵的类如下:

    int spot;
    int side;
    int [][]table;
    boolean[] sure;
    public  tu(int e)
    {
        this.spot=e;
        this.table=new int[e][e];
        for(int i=0;i<e;i++)
            for(int j=0;j<e;j++)
                this.table[i][j]=10000;
    }

因为两图的点都是有序从0/1开始递增,故我默认点中最小值为0,最大值为(点数目-1),而初始化的权重为10000,方便后续算法调用。而sure数组是我额外添加便于确保某个点是否已经进入/被搜索过。

创建矩阵如下:

    public void tablefull(int []a)
    {
        this.table[a[0]][a[1]]=a[2];
        this.table[a[1]][a[0]]=a[2];
    }
    public  void create(int e)
    {
        this.sure=new boolean[this.spot];
        for(int i=0;i<this.spot;i++)
            this.sure[i]=false;

        this.side=e;
        Scanner scan=new Scanner(System.in);
        for(int i=0;i<e;i++)
        {
            System.out.print("请输入两个点以及它们的权重:");
            int []a=new int[3];//输入两个点和权重
            a[0]=scan.nextInt();
            a[1]=scan.nextInt();
            a[2]=scan.nextInt();
            this.tablefull(a);
        }
    }

tablefull函数可以建立也可以不建立,只是当时为了看着舒服才额外开了另一个算法去存进数据。

一.深度搜索

DFS算法,以深度优先,即先从出发点开始,然后进入出发点第一个连接的点,然后连接点的查找第一个查找到的点(不能是已经搜索过的点),当去到某个点它所连接的点都已经搜索过,则返回,然后返回,让上级点查找另外的点进行再深层的搜索,直到全部搜索完。
在这里插入图片描述
因此不需要额外借助如栈,队列之类的,只需要本身即可完成,而代码也十分简短。
传入的参数e为出发点,而我实验过程中默认从0号结点(即图中最小值)出发。

    public void DFS(int e)
    {
        this.sure[e]=true;
        System.out.println(e+" ");
        int a=-1;
        for(int i=0;i<this.spot;i++)
        {
            if(this.table[e][i]<10000&&!this.sure[i])
            {
                a=i;
                DFS(a);
            }
        }
    }

二.广度搜索

广度搜索,以搜索完该结点相连的结点后,再进入下标最接近那个点的其他未搜索过的点,重复此步骤直到所有点都搜索完,故需要借助队列存储从某结点出发时,先进入的结点。
队列类如下:

public class queue {
    queue front;
    queue rear;
    queue next;
    int e;
    public queue()//初始化头结点
    {
        front=this;
        rear=this;
        next=null;
    }
    public queue(int e)
    {
        this.e=e;
        next=null;
        front=null;
        rear=null;
    }
    public void put(int e)//放入队列
    {
        queue a=new queue(e);
        this.rear.next=a;
        this.rear=a;
    }
    public boolean empty()//检测是否为空
    {
        queue pre=this;
        if(pre.rear==pre.front)
            return true;
        return false;
    }
    public void clear()//清空队列
    {
        this.rear=front;
        this.next=null;
    }
    public int delete()//删除队首元素
    {

        queue pre=this;
        if(pre.empty())
            return -1;
        queue last=pre.front.next;
        int a=last.e;
        pre.next=last.next;
        return a;
    }
}

该类和前天做的队列实验差不多,只不过把没用上的去掉;用上的保留。
在这里插入图片描述我的广度搜索如图进行。步骤为:搜索完本结点,搜索相邻结点并按顺序加入进队列;完事后从队首提取出结点,搜索该结点的相邻且没搜索过的结点;按此步骤循环进行直到搜索结束。

{
        queue q=new queue();
        System.out.print((e+1)+" ");
        this.sure[e]=true;
        do
        {
            for(int i=0;i<this.spot;i++)
                if(this.table[e][i]<10000&&!this.sure[i])
                {
                    System.out.print((i+1)+" ");
                    q.put(i);
                    this.sure[i]=true;
                }
            e=q.delete();
        }while(this.notalltrue()&&!q.empty());
        q.clear();
    }

notalltrue函数用于判断是否所有点都搜索过,如下:

    public boolean notalltrue()
    {
        for(int i=0;i<this.spot;i++)
            if(!this.sure[i])
                return true;
         return  false;
    }

三.最小生成树算法:Prim

Prim算法步骤:从出发点开始查找相邻点中权重最小的点,相连;然后从已相连的点中,查找和未相连的点中权重最小的点相连;重复步骤直到所有的点都连起来。
在这里插入图片描述(图源某度搜索)

    public void Prim(int e)
    {
        int []visited=new int[this.spot];
        System.out.println("起点是"+(e+1));
        this.sure[e]=true;
        visited[0]=e;
        int len=1;

        while(this.notalltrue())
        {
            int index=-1;//存储点位置
            int min=10000;//存储两点值
            for(int j=0;j<len;j++)
            {
                for(int i=0;i<this.spot;i++)
                    if(this.table[visited[j]][i]<min&&!this.sure[i])
                    {

                        min=this.table[visited[j]][i];
                        index=i;
                    }
            }
            e=index;
            System.out.println("下一个点为"+(e+1));
            this.sure[e]=true;
            visited[len]=e;
            len++;
        }
    }

我的算法实现,是先输出了出发点,然后查询在visited数组中的点,从里面的点中找权重最小的点。(visited数组用于记录已搜索过的点)。sure数组用于确定某点是否已搜索,和notalltrue函数搭配(判断是否所有的点都遍历过)使用。

四.最短路径:Dijkstra

Dijkstra算法:我的思路是:先确定好出发点,然后通过出发点到各点的距离生成一个最短路径shortpath数组,非直接连接的置10000,自己的点置0。然后从出发点开始查找,先查找shortpath中权重最小且非本身点的点,然后确定为到那个点的最短路径。然后从那个点出发,计算那个点到相邻点的距离,再加上shortpath中那个点对应的数值,若比shortpath数组中到其他点的数值变小,则置换掉。然后选择shortpath数组中,未确定为最短路径的点,置为下次从那个点开始出发。直到ifsure数组(确定点是否已经找到最短路径),全为true;visited数组满了(按顺序放入已搜索过的点);即可结束。

    public void Dijkstra(int e)
    {
        int []shortpath=new int[this.spot];//最短路径数值
        int []visited=new int[this.spot];//已确定最短路径的集合
        boolean []ifsure=new boolean[this.spot];
        for(int i=0;i<this.spot;i++)
        {
            ifsure[i]=false;
            shortpath[i]=this.table[e][i];
        }
        visited[0]=e;
        ifsure[e]=true;
        int min=0;
        for(int i=1;i<this.spot;i++)
            if(shortpath[min]>shortpath[i])
                min=i;
        shortpath[e]=0;
        for(int i=1;i<this.spot;i++)
        {
            visited[i]=min;
            ifsure[min]=true;
            int max=10000;
            for(int j=0;j<this.spot;j++)
            {
                if(shortpath[j]>shortpath[min]+this.table[min][j]&& !ifsure[j])
                    shortpath[j]=shortpath[min]+this.table[min][j];
            }

            int j=0;
            for(;j<this.spot;j++)
                if(!ifsure[j])
                {
                    max=shortpath[j];
                    min=j;
                    break;
                }
            for(;j<this.spot;j++)
            {
                if(shortpath[j]<max&&!ifsure[j])
                {
                    max=shortpath[j];
                    min=j;
                }
            }
        }
        for(int i=0;i<this.spot;i++)
            System.out.print((visited[i])+" ");

    }

总结

算法是根据两幅图进行编写,也通过了两幅图的实现,所以应该不存在问题。
Kruskal算法本来也想实现的,不过时间不够,而且时间范围内肝不出来,遂打算后补。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值