代码改变世界

广义表(1)

2011-01-22 15:12  Clingingboy  阅读(1154)  评论(0编辑  收藏  举报

 

参考:http://blog.csdn.net/fan158/archive/2010/05/21/5613821.aspx

感谢这位作者

概念

即表中的元素可以为单个元素,同时也可以是一个表.可以说是表中有表。如下数据

A=(a,b,c,d)

B=(a,(b,c),d)

C=(a,(b,(c,d),e))

单个元素称为原子,表为子表,如B的a为原子,(b,c)为子表

将字符串转义为数组

string str = "a,b,c,d";

如上数组,若要转成数组,那么就预先要知道其大小.或者以链表方式表示

如下示例

(1)预先算数组长度

string str = "a,b,c,d";

var strLength = str.Length / 2 + 1;
char[] strArr = new char[strLength];
int j = 0;
for (int i = 0; i < strLength; i++)
{
    strArr[i] = str[j];
    j += 2;
}

(2)用链表

string str = "a,b,c,d";
int i=0;
Link<char> first = null;
Link<char> currentLink = null;
while (i < str.Length)
{
    char alphabet = str[i];
    var link = new Link<char>() { Value = alphabet };
    
    if (i == 0)
    {
        first = link;
        currentLink = link;
    }
    else
    {
        currentLink.Next = link;
        currentLink = currentLink.Next;
    }
    i+=2;
}

(3)递归法

public class LinkCreater
{
    private int i = 0;
    Link<char> first = null;
    private string _str;
    public LinkCreater(string str)
    {
        _str = str;
    }

    public void CreatLink()
    {
        CreatLink(null);
    }

    public void CreatLink(Link<char> node)
    {
        if (i > _str.Length) return;
        var alphabet = _str[i];
        i += 2;
        var link=new Link<char>() { Value = alphabet };
        if (node == null)
        {
            first = link;
        }
        else
        {
            node.Next = link;
        }
        CreatLink(link);
    }
}
 
(4)有返回值的递归
public Link<char> CreatLink()
{
    if (i > _str.Length) return first;
    var alphabet = _str[i];
    i += 2;
    var link = new Link<char>() { Value = alphabet };
    link.Next = CreatLink();
    first = link;
    return first;
}
 
返回值会一直从字符串末端开始创建直到头结点

构建广义表

数据结构如下

public enum NodeType { Atom, List }

public class GLNode<T>
{
    public NodeType Type { get; set; }
    public GLNode<T> Next { get; set; }
    public object Item { get; set; } //Save list or T in it by Type.  
}

如下数据,将其看成3个元素,当遇到子表则以相同方法递归创建子表

A=a,(b,c),f

子表创建规则:

  1. 若遇左括号(则创建子表
  2. 若遇到右括号则子表结束
  3. 其他状况则认为是一个原子

即除了元素之外有三种符号(),,

A=a,(b,c),f

第一步

node = new GLNode<char>();
switch (t)
{
    case '(':
        node.Type = NodeType.List;
        node.Item = Create();
        break;
    case ')':
        node = null;
        break;
    default:
        node.Type = NodeType.Atom;
        node.Item = t;
        break;
}

1.a为Atom

2.字符前进一步,判断符号

t = this._CharArray[i++];// For Next.  
if (node != null)
{
    switch (t)
    {
        case ',':
            node.Next = Create();
            break;
        default:
            node.Next = null;
            break;
    }
}

3.再次进入Create方法

4.创建子表

5….不断递归

public GLNode<char> Create()
{
    GLNode<char> node = null;

    char t = this._CharArray[i];
    i++;
    if (i <= this._CharArray.Length)
    {
        node = new GLNode<char>();
        switch (t)
        {
            case '(':
                node.Type = NodeType.List;
                node.Item = Create();
                break;
            case ')':
                node = null;
                break;
            default:
                node.Type = NodeType.Atom;
                node.Item = t;
                break;
        }
    }
    else
    {
        return CreateReturn(node);
    }

    if (i == this._CharArray.Length)
        return CreateReturn(node);

    t = this._CharArray[i++];// For Next.  
    if (node != null)
    {
        switch (t)
        {
            case ',':
                node.Next = Create();
                break;
            default:
                node.Next = null;
                break;
        }
    }

    return CreateReturn(node);
}

private GLNode<char> CreateReturn(GLNode<char> node) 
{ 
    return this._Root = node;
}

获取广义表深度

若遇到子表则向下探测(深度+1),并与父表(根)的最大深度比较,取大值

public int GetDepth()
{
    return GetDepth(_Root);
}

public int GetDepth(GLNode<char> node)
{
    int max, depth;

    if (node == null) return 1;

    if (node.Next == null && node.Item == null) return 1;

    for (max = 0; node != null; node = node.Next)
    {
        if (node.Type == NodeType.List)
        {
            depth = GetDepth((GLNode<char>)node.Item);

            if (depth > max) max = depth;
        }
    }

    return max + 1;
}

输出广义表

public string Write()
{
    return this.Write(this._Root);
}
public string Write(GLNode<char> node)
{
    StringBuilder sb = new StringBuilder();

    switch (node.Type)
    {
        case NodeType.Atom:
            sb.AppendFormat("{0}", node.Item.ToString());
            break;
        case NodeType.List:
            sb.Append('(');
            if (node.Item != null)
                sb.Append(Write((GLNode<char>)node.Item));
            sb.Append(')');
            break;
    }

    if (node.Next != null)
    {
        sb.Append(",");
        sb.Append(Write(node.Next));
    }

    return sb.ToString();
}

以上主要用到了递归的方法.也可以将递归的方法写在GLNode里面,让其自身调用输出方法,这样理解起来更好理解

求表头和表尾

如果同用一个引用地址的话,就非常简单,表头就是第一个元素,剩下的就是表尾了.

否则的话就需要拷贝其中的的数据,同样还是递归

public GLNode<char> GetHead(GLNode<char> node)
{
    if (IsEmpty(node)) return null;

    var item = new GLNode<char>();
    item.Type = node.Type;
    item.Item = node.Item;
    return item;
}

public GLNode<char> GetTail(GLNode<char> node)
{
    if (IsEmpty(node)) return null;

    var temp = new GLNode<char>();
    return temp = Copy(node.Next);
}

public GLNode<char> Copy(GLNode<char> node)
{
    GLNode<char> temp = null;

    if (node != null)
    {
        temp = new GLNode<char>();
        temp.Type = node.Type;

        switch (temp.Type)
        {
            case NodeType.Atom:
                temp.Item = node.Item;
                break;
            case NodeType.List:
                temp.Item = Copy((GLNode<char>)node.Item);
                break;
        }

        temp.Next = Copy(node.Next);
    }

    return temp;
}