我们认为最简单的树组织形式是非平衡二叉树。树内部的结点用{Key,Vlue,Smaller,Bigger}来表示。Value是被存储在树的一些结点中对象的值,它的键为Key。Smaller是一棵子树,它的所有结点的键值都小于Key,Bigger也是一棵子树,它的所有结点的键值都大于或等于Key。树的叶子用原子式nil表示。
我们从lookup(Key,Tree)函数开始,这个函数搜索Tree以确定树中是否有与Key相关的项。
函数insert(Key,Value,OldTree)将数据Key-Value添加到树OldTree中,并返回一棵新树。
- insert(Key, Value, nil) ->
- {Key,Value,nil,nil};
- insert(Key, Value, {Key,_,Smaller,Bigger}) ->
- {Key,Value,Smaller,Bigger};
- insert(Key, Value, {Key1,V,Smaller,Bigger}) when Key < Key1 ->
- {Key1,V,insert(Key, Value, Smaller),Bigger};
- insert(Key, Value, {Key1,V,Smaller,Bigger}) when Key > Key1 ->
- {Key1,V,Smaller,insert(Key, Value, Bigger)}.
第一个子句得到数据,并插入到一棵新树当中,第二个子句将复写已经存在的结点,第三个和第四个子句确定当Key的值小于、大于或等于树中当前结点的Key时,应该采取什么样的行为。
- write_tree(T) ->
- write_tree(0, T).
- write_tree(D, nil) ->
- io:tab(D),
- io:format('nil', []);
- write_tree(D, {Key,Value,Smaller,Bigger}) ->
- D1 = D + 4,
- write_tree(D1, Bigger),
- io:format('~n', []),
- io:tab(D),
- io:format('~w ===> ~w~n', [Key,Value]),
- write_tree(D1, Smaller).
我们可以用一个测试函数将数据插入到树中,并把它打印出来:
图4.1 一棵非平衡二叉树
- nil
- 12 ===> fred
- 9 ===> susan
- nil
- 8 ===> dan
- nil
- 7 ===> kalle
- nil
- 6 ===> thomas
- nil
- 5 ===> rickard
- nil
- 4 ===> joe
- nil
- 3 ===> jane
- nil
- 2 ===> tobbe
- nil
注意这棵树并不是十分“平衡”。按照严格的顺序插入键的队列,比如像这样:
- T1 = nil,
- T2 = insert(1,a,T1),
- T3 = insert(2,a,T2),
- T4 = insert(3,a,T3),
- T5 = insert(4,a,T4),
- ...
- T9 = insert(8,a,T8).
使这棵树看起来变成了一个列表(见图4.2)。
图4.2 变化后的非平衡二叉树
我们也需要能够删除二叉树内的元素:
- delete(Key, nil) ->
- nil;
- nil;
- delete(Key, {Key,_,Smaller,nil}) ->
- Smaller;
- delete(Key, {Key,_,nil,Bigger}) ->
- Bigger;
- delete(Key, {Key1,_,Smaller,Bigger}) when Key == Key1 ->
- {K2,V2,Smaller2} = deletesp(Smaller),
- {K2,V2,Smaller2,Bigger};
- delete(Key, {Key1,V,Smaller,Bigger}) when Key < Key1 ->
- {Key1,V,delete(Key, Smaller),Bigger};
- delete(Key, {Key1,V,Smaller,Bigger}) when Key > Key1 ->
- {Key1,V,Smaller,delete(Key, Bigger)}.
当要删除的结点是树中的叶子,或者在这个结点下面只有一颗子树时,删除操作是很容易的(子句1到4)。子句6和7中,要删除的结点并没有被确定位置,而是继续在合适的子树中向前搜索。
在子句5当中,要删除的结点被找到,但是它是树中的一个内部结点(例如结点同时有Smaller和Bigger子树)。这种情况下,Smaller子树中具有最大键的结点将被删除,并且整棵树在这个点重建。
- deletesp({Key,Value,nil,nil}) ->
- {Key,Value,nil};
- deletesp({Key,Value,Smaller,nil}) ->
- {Key,Value,Smaller};
- deletesp({Key,Value,Smaller,Bigger}) ->
- {K2,V2,Bigger2} = deletesp(Bigger),
- {K2,V2,{Key,Value,Smaller,Bigger2}}.