数据结构java(十二)图②邻接表实现(一维数组+链表)

本文介绍了如何使用Java通过邻接表数据结构来实现图的存储,详细讲解了一维数组结合链表的方式。
摘要由CSDN通过智能技术生成

 1.邻接表实现(GraphAdjList)

import java.lang.reflect.Array;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;


/**
 *  稀疏图
 *  邻接表实现
 * @author Administrator
 */
public class GraphAdjList<E> implements IGraph {


    /**
     * 邻接表中表对应的链表的结点
     */
    private static class ENode{
        /**
         * 邻接顶点序号
         */
        int adjvex;
        /**
         * 存储边或弧相关的信息,如权值
         */
        int weight;
        /**
         * 下一个邻接表结点
         */
        ENode nextadj;

        /**
         *
         * @param adjvex
         * @param weight
         */
        public ENode(int adjvex, int weight) {
            this.adjvex = adjvex;
            this.weight = weight;
        }
    }

    /**
     * 邻接表中表的顶点
     * @param <E>
     */
    private static class VNode<E>{
        /**
         * 顶点信息
         */
        E data;
        /**
         * 邻接表的第一个结点
         */
        ENode firstadj;

        public VNode(E data) {
            this.data = data;
        }
    }


    /**
     * 顶点数组,每个元素都是一个VNode结构 顶点信息+结点(顶点序号+下一个邻接表的结点)
     */
    private VNode<E>[] vexs;
    /**
     * 顶点的实际数量
     */
    private int numOfVexs;
    /**
     * 顶点的最大数量
     */
    private int maxNumOfVexs;
    /**
     * 判断顶点是否被访问过
     */
    private boolean[] visited;


    @SuppressWarnings("unchecked")
    public GraphAdjList(int maxNumOfVexs) {
        this.maxNumOfVexs = maxNumOfVexs;
        vexs = (VNode<E>[]) Array.newInstance(VNode.class, maxNumOfVexs);
    }

    /**
     * 获取顶点的个数
     *
     * @return
     */
    @Override
    public int getNumOfVertex() {
        return numOfVexs;
    }

    /**
     * 插入顶点
     *
     * @param v
     * @return
     */
    @Override
    public boolean insertVex(Object v) {
        //数组已满
        if (numOfVexs>=maxNumOfVexs){
            return false;
        }
        VNode<E> vex = new VNode<>((E) v);
        vexs[numOfVexs++] = vex;
        return true;
    }

    /**
     * 删除顶点
     *
     * @param v
     * @return
     */
    @Override
    public boolean deleteVex(Object v) {
        return false;
    }

    /**
     * 定位顶点的位置
     *
     * @param v
     * @return
     */
    @Override
    public int indexOfVex(Object v) {
        for (int i = 0;i<numOfVexs;i++){
            if (vexs[i].data.equals(v)){
                return i;
            }
        }
        return -1;
    }

    /**
     * 定位指定位置的顶点
     *
     * @param v
     * @return
     */
    @Override
    public Object valueOfVex(int v) {
        if (v<0|| v>=numOfVexs){
            return null;
        }
        return vexs[v].data;
    }

    /**
     * 插入边  无向无权图
     *
     * @param v1
     * @param v2
     * @param weight
     * @return
     */
    @Override
    public boolean insertEdge(int v1, int v2, int weight) {
        if (v1 < 0 || v2 < 0 || v1 >= numOfVexs || v2 >= numOfVexs){
            throw new ArrayIndexOutOfBoundsException();
        }
        insertDo(new ENode(v2, weight), vexs[v1]);

        //双向
        insertDo(new ENode(v1, weight), vexs[v2]);


        return true;
    }

    /**
     *  vex-->node
     * @param node  链式的新结点
     * @param vex   顶点
     */
    private void insertDo(ENode node, VNode<E> vex) {
        // 索引为index2的顶点没有邻接顶点
        if (vex.firstadj == null) {
            vex.firstadj = node;
        }
        // 索引为index1的顶点有邻接顶点
        else {
            node.nextadj = vex.firstadj;
            vex.firstadj = node;
        }
    }

    /**
     * 插入边 考虑什么类型
     * 1:无向无权图
     * 2:无向有权图
     * 3:有向无权图
     * 4:有向有权图
     *
     * @param edgeElement
     * @return
     */
    @Override
    public boolean insertEdge(EdgeElement edgeElement) {
        return false;
    }

    /**
     * 删除边
     *
     * @param v1
     * @param v2
     * @return
     */
    @Override
    public boolean deleteEdge(int v1, int v2) {
        if (v1 < 0 || v2 < 0 || v1 >= numOfVexs || v2 >= numOfVexs){
            throw new ArrayIndexOutOfBoundsException();
        }
        // 删除索引为index1的顶点与索引为index2的顶点之间的边 v1-v2

        ENode current = vexs[v1].firstadj;//v2当前结点的下一个结点

        ENode previous = null;//v2当前结点,
        while (current != null && current.adjvex !=v2){
            //v2当前结点,
            previous = current;
            current = current.nextadj;
        }
        if (current !=null) {
            //删除操作
            previous.nextadj = current.nextadj;
            current = null;//垃圾回收此结点
        }
        // 删除索引为index2的顶点与索引为index1的顶点之间的边 v2-v1
        current = vexs[v2].firstadj;
        while (current != null && current.adjvex != v1){
            previous = current;
            current  = current.nextadj;
        }

        if (current!=null){
            previous.nextadj = current.nextadj;
            current = null;
        }
        return true;
    }

    /**
     * 查找边
     *
     * @param v1
     * @param v2
     * @return
     */
    @Override
    public int getEdge(int v1, int v2) {
        if (v1 < 0 || v2 < 0 || v1 >= numOfVexs || v2 >= numOfVexs) {
            throw new ArrayIndexOutOfBoundsException();
        }
        //第一个结点
        ENode current = vexs[v1].firstadj;

        while (current != null){
            if (current.adjvex == v2){
                return current.weight;
            }
            current = current.nextadj;
        }
        return 0;
    }

    /**
     * 深度优先搜索遍历(递归栈实现)
     *
     * @param v
     * @return
     */
    @Override
    public String depthFirstSearchByDG(int v) {

        return null;
    }

    /**
     * 深度优先搜索遍历(非递归栈实现)
     *
     * @param v
     * @return
     */
    @Override
    public String depthFirstSearch(int v) {
        if (v < 0 || v >= numOfVexs) {
            throw new ArrayIndexOutOfBoundsException();
        }
        visited =  new boolean[numOfVexs];
        StringBuilder sb = new StringBuilder();
        Stack<Integer> stack = new Stack();
        stack.push(v);
        visited[v] = true;

        ENode current;
        while (!stack.isEmpty()){
            v = stack.pop();
            sb.append(vexs[v].data+",");
            current = vexs[v].firstadj;

            while (current != null ){
                if (!visited[current.adjvex]){
                    stack.push(current.adjvex);
                    visited[current.adjvex] = true;
                }
                current = current.nextadj;
            }
        }
        return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : null;
    }

    /**
     * 广度优先搜索遍历
     *
     * @param v
     * @return
     */
    @Override
    public String breadFirstSearch(int v) {
        if (v < 0 || v >= numOfVexs) {
            throw new ArrayIndexOutOfBoundsException();
        }
        visited = new boolean[numOfVexs];
        StringBuilder sb = new StringBuilder();
        Queue<Integer> queue = new LinkedList<>();

        queue.offer(v);
        visited[v]=true;

        ENode current;
        while (!queue.isEmpty()){
            v = queue.poll();
            sb.append(vexs[v].data+",");
            current = vexs[v].firstadj;

            while (current!=null){
                if (!visited[current.adjvex]){
                    queue.offer(current.adjvex);
                    visited[current.adjvex] = true;
                }
                current = current.nextadj;
            }

        }
        return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : null;
    }

    /**
     * 查找源点到其它顶点的路径
     *
     * @param v
     * @return
     */
    @Override
    public int[] dijkstra(int v) {
        out();
        if (v < 0 || v >= numOfVexs) {
            throw new ArrayIndexOutOfBoundsException();
        }
        //初始化false
        boolean[] st = new boolean[numOfVexs];
        //存放源点到其他点的距离
        int[] distance = new int[numOfVexs];
        //初始化全为无穷大
        for (int i = 0; i<numOfVexs;i++){
            distance[i] = Integer.MAX_VALUE;
        }


        ENode current;
        current = vexs[v].firstadj;

        out(st,distance);
        while (current!=null){
            distance[current.adjvex] = current.weight;
            current =current.nextadj;
        }



        distance[v] = 0;
        st[v] = true;

        //处理从源点到其余顶点的最短路径
        for (int i = 0;i<numOfVexs;i++) {
            int min = Integer.MAX_VALUE;
            int index = -1;
            //比较从源点到其余顶点的路径长度
            for (int j = 0; j < numOfVexs; j++) {
                //从源点到j顶点的最短距离还没有找到 //从源点到j顶点的最小路径
                if (!st[j] && distance[j] < min) {
                    index = j;
                    min = distance[j];
                }
            }

            out(st, distance);
            //找到源点到索引为index顶点的最短路径
            if (index != -1) {
                st[index] = true;
            }

            //更新当前最短路径及距离
            for (int w = 0; w < numOfVexs; w++) {
                if (!st[w]) {
                    current = vexs[w].firstadj;
                    while (current != null) {
                        if (current.adjvex == index  && (min + current.weight) < distance[w]) {
                            distance[w] = min + current.weight;
                            break;
                        }
                        current = current.nextadj;
                    }
                }
            }
        }
        return distance;
    }


    private void out(boolean[] st, int[] distance) {
        System.out.printf("%s\t\t%s\t\t%s\t\t\n","顶点","距离","是否访问");
        for (int i=0; i<numOfVexs;i++) {
            System.out.printf("%s\t\t",vexs[i].data);
            System.out.printf("%d\t\t",distance[i]);
            System.out.printf("%b\t\t",st[i]);
            System.out.println();
        }
    }

    /**
     * 打印二维数组边的权值
     */
    @Override
    public void out() {
        ENode current;
        for (int i = 0 ;i<numOfVexs;i++) {
            System.out.print(vexs[i].data);
            current = vexs[i].firstadj;
            while (current != null){
                System.out.print("--->("+vexs[current.adjvex].data+","+current.weight+")");
                current = current.nextadj;
            }
            System.out.println();
        }

    }
}

2.测试 


import org.junit.Before;
import org.junit.Test;

/**
 * 连接矩阵
 * @author Administrator
 */
public class GraphAdjListTest {

    private GraphAdjList graphAdjList;

    @Before
    public void setUp() throws Exception {
        graphAdjList = new GraphAdjList(10);

        graphAdjList.insertVex("A");
        graphAdjList.insertVex("B");
        graphAdjList.insertVex("C");
        graphAdjList.insertVex("D");
        graphAdjList.insertVex("E");
        graphAdjList.insertVex("F");
        graphAdjList.insertVex("G");
        graphAdjList.insertVex("H");
        graphAdjList.insertVex("I");

        graphAdjList.insertEdge(graphAdjList.indexOfVex("A"),graphAdjList.indexOfVex("B"),1);
//        out();
        graphAdjList.insertEdge(graphAdjList.indexOfVex("A"),graphAdjList.indexOfVex("D"),3);
        graphAdjList.insertEdge(graphAdjList.indexOfVex("A"),graphAdjList.indexOfVex("E"),2);
        graphAdjList.insertEdge(graphAdjList.indexOfVex("B"),graphAdjList.indexOfVex("D"),5);
        graphAdjList.insertEdge(graphAdjList.indexOfVex("B"),graphAdjList.indexOfVex("C"),1);
        graphAdjList.insertEdge(graphAdjList.indexOfVex("C"),graphAdjList.indexOfVex("F"),7);
        graphAdjList.insertEdge(graphAdjList.indexOfVex("D"),graphAdjList.indexOfVex("G"),2);
        graphAdjList.insertEdge(graphAdjList.indexOfVex("E"),graphAdjList.indexOfVex("G"),9);
        graphAdjList.insertEdge(graphAdjList.indexOfVex("G"),graphAdjList.indexOfVex("H"),1);
        graphAdjList.insertEdge(graphAdjList.indexOfVex("H"),graphAdjList.indexOfVex("I"),3);


    }

    @Test
    public void getNumOfVertex() {
    }

    @Test
    public void insertVex() {
    }

    @Test
    public void deleteVex() {
    }

    @Test
    public void indexOfVex() {
    }

    @Test
    public void valueOfVex() {
    }

    @Test
    public void insertEdge() {
    }

    @Test
    public void insertEdge1() {
    }

    @Test
    public void deleteEdge() {
    }

    @Test
    public void getEdge() {
    }

    @Test
    public void depthFirstSearchByDG() {
    }

    @Test
    public void depthFirstSearch() {
        String s = graphAdjList.depthFirstSearch(0);
        System.out.println(s);

    }

    @Test
    public void breadFirstSearch() {
        String s = graphAdjList.breadFirstSearch(0);
        System.out.println(s);
    }

    @Test
    public void dijkstra() {
        int[] dijkstra = graphAdjList.dijkstra(0);
        for (int i : dijkstra) {
            System.out.print(i+",");
        }
    }

    @Test
    public void out() {
        graphAdjList.out();
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值