参考: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
子表创建规则:
- 若遇左括号(则创建子表
- 若遇到右括号则子表结束
- 其他状况则认为是一个原子
即除了元素之外有三种符号(),,
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; }