数据结构基础(三)广义表

广义表是线性表的推广。区别在于:线性表的元素仅限于原子项;而广义表的元素即可以是原子项,也可以是广义表。

概念

定义

广义表是n (n>=0)个元素a1,a2,a3,…,an的有限序列,其中ai或者是原子项,或者是一个广义表(子表)。不为空时,a1为表头(Header),其余元素组成的表(a2,a3,……,an)是LS的表尾(Tail)

结构

采用链式结构,节点分为原子节点(tag,atom),以及表节点(tag,hp,tp)
tag:0为原子节点,1为表节点
atom:原子节点的值
hp:子表表头
tp:子表表尾

递归特性

由表头、表尾的定义可知:任何一个非空广义表其表头可能是原子,也可能是列表,而其表尾必定是列表。每个表尾又可以继续分为表头,表尾……

实现代码

注意点:

  • 代码中实现了广义表的创建,插入,获取深度、长度,输出广义表字符串等功能。
  • 采用了递归思想实现创建,获取深度。
    依照广义表定义,创建时可以每次把字符串分为表头和表尾,依次创建每个表头的节点,最终实现广义表。但考虑到这样做递归次数太多,代码中修改成只递归表节点。
package test;

import java.util.ArrayList;
import java.util.List;

/**
 * 广义表
 */
public class GList {

    /**
     * 广义表的头节点
     */
    private Node hNode;
    /**
     * 广义表的尾部节点,方便添加节点
     */
    private Node lastNode;
    /**
     * 广义表长度
     */
    private int length = 0;;

    /**
     * 广义表节点
     */
    private static class Node {
        // 0为值节点,1为广义表节点
        public int tag;
        //原子节点使用的值域
        public String atom;
        //表节点使用的表头
        public Node hp;
        //指向下一个节点
        public Node tp;

        public Node(int tag, String atom) {
            this.tag = tag;
            this.atom = atom;
        }

        public Node(int tag, Node hp) {
            this.tag = tag;
            this.hp = hp;
        }

    }

    /**
     * 空构造
     */
    public GList() {
        hNode = lastNode = null;
    }

    /**
     * 依据字符串构造出广义表
     * 
     * @param gl
     */
    public GList(String gl) {
        hNode = createGList(gl);
        lastNode = getTailNode();
    }

    /**
     * 返回广义表长度
     * 
     * @return
     */
    public int getLength() {
        return length;
    }

    /**
     * 向广义表中添加元素
     * @param n
     */
    public void add(Node n) {
        length++;
        if (lastNode == null) {
            hNode = lastNode = n;
            return;
        }
        lastNode = lastNode.tp = n;
    }

    /**
     * 返回广义表头节点
     * @return
     */
    public Node getHead() {
        return hNode;
    }

    /**
     * 返回广义表尾部节点
     * @return
     */
    public Node getTailNode() {
        if (lastNode != null)
            return lastNode;

        Node n = hNode;
        length = 1;
        while (n != null && n.tp != null) {
            n = n.tp;
            length++;
        }
        return n;
    }
    /**
     * 返回广义表的尾节点
     * @return
     */
    public GList getTail() {
        GList gList=new GList();
        gList.hNode=hNode.tp;
        return gList;
    }

    /**
     * 获取广义表深度
     * @return
     */
    public int getGListDepth() {
        if (hNode == null)
            return 0;
        return 1 + getDepth(hNode);
    }

    @Override
    public String toString() {
        return doList(hNode);
    }

    /**
     * 以一节点为头节点获取深度
     * @param n
     * @return
     */
    private int getDepth(Node n) {
        if (n == null)
            return 0;
        //如为原子节点则深度为0,表节点=子表深度加1
        int depth = (n.tag == 0 ? 0 : 1 + getDepth(n.hp));
        //递归比较相邻节点深度
        int depthNext = getDepth(n.tp);
        return depth > depthNext ? depth : depthNext;
    }

    /**
     * 以一节点为头节点返回生成的广义表字符串
     * @param n
     * @return
     */
    private String doList(Node n) {
        if (n == null)
            return null;
        String result = "(";
        boolean isBegin = false;
        while (n != null) {
            //原子节点直接拼接其atom值
            if (n.tag == 0) {
                if (isBegin == false) {
                    result += n.atom;
                    isBegin = true;
                } else {
                    result += "," + n.atom;
                }
            } 
            //表节点进行递归
            else {
                if (isBegin == false)
                    result += doList(n.hp);
                else {
                    result += "," + doList(n.hp);
                }
            }
            n = n.tp;
        }
        result = result.substring(0, result.length()) + ")";
        return result;
    }

    /**
     * 根据字符串生成广义表
     * @param gl
     * @return 返回生成广义表的头结点
     */
    private Node createGList(String gl) {
        Node hN = null;
        Node n = null;
        //获取初步分割后的节点集合,此时表节点atom为表字符串,hp未指定
        List<Node> list = splitGL(gl);

        int size = list.size();
        //将表节点hp指定,并连接相邻节点
        for (int i = 0; i < size; i++) {
            n = list.get(i);
            if (n.tag == 1) {
                n.hp = createGList(n.atom);
            }
            if (i > 0)
                list.get(i - 1).tp = n;
        }
        hN = list.get(0);
        return hN;
    }

    /**
     * 将广义表字符串单元分割,每个划分单元放入一个Node,划分的字符串放入Node.atom
     * @param gl
     * @return
     */
    private List<Node> splitGL(String gl) {
        // 去除左右两边括号
        gl = gl.substring(1, gl.length() - 1).trim();
        // 最后加上','方便末尾片段的分割
        char[] gchar = (gl + ",").toCharArray();
        //标记分割字符单元有几个括号
        int flag = 0;
        //分割字符单元生成的Node集合
        List<Node> list = new ArrayList<Node>();
        //分割字符单元
        String segment = "";

        for (int i = 0; i < gchar.length; i++) {
            if (gchar[i] == '(')
                flag++;
            else if (gchar[i] == ')')
                flag--;
            //若一个字符单元结束
            if ((gchar[i] == ',' && flag == 0)) {
                if (segment.contains("("))
                    list.add(new Node(1, segment));
                else
                    list.add(new Node(0, segment));
                segment = "";
                continue;
            }
            segment += gchar[i];
        }

        return list;
    }

    public static void main(String[] args) {
        GList gList = new GList(
                "(aa,(aa,bb,cc,(aaa)),c,(aa,(ccc,(eeee)),dd),k)");
        gList.add(new Node(0, "haha"));
        System.out.println(gList);
        System.out.println(gList.getGListDepth());
        System.out.println(gList.getLength());
        System.out.println("-----------------");
        GList gList2 = new GList("(a,b)");
        System.out.println(gList2);
        System.out.println(gList2.getGListDepth());
        System.out.println(gList2.getLength());

    }

}/**output:
(aa,(aa,bb,cc,(aaa)),c,(aa,(ccc,(eeee)),dd),k,haha)
4
6
-----------------
(a,b)
1
2*/
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值