使用单节点构成2-3-4树

2-3-4树

	2-3-4树称为(2,4)树,满足两点:
	·大小属性:每个内部节点最多有4个孩子
	·深度属性:所有外部结点具有相同的深度

2-3-4树如图:
使用单节点构成2-3-4树
对2-3-4树的详细方法不进行叙述。
在树中使用单个结点搭建上图结构,令h3位_root,h1和h4非别为各自的_head结点。

单个结点图:

每个结点有四个指针
使用单节点构成2-3-4树

大致结构图:

保证每个节点的四个指针都指向其他结点或None
使用单节点构成2-3-4树

添加结点:

对应代码中的_up_split方法

如果添加结点后导致不满足大小属性时进行分裂操作:
使用单节点构成2-3-4树
如图此时k1,k2,k3,k4以k1为head,但此时不满足大小属性,将k3分裂添加到h1后。
使用单节点构成2-3-4树
分裂后:
使用单节点构成2-3-4树

删除结点:

对应代码中的_down_split方法

如果删除后导致外部结点不在同一深度时,有两种情况。

Case1: 兄弟结点不为单结点
使用单节点构成2-3-4树
此时将被删除结点、父节点、兄弟结点进行如下交换:
使用单节点构成2-3-4树
交换后为:
使用单节点构成2-3-4树

Case2 兄弟结点为单结点
使用单节点构成2-3-4树
此时将结点14和15做如下结点交换并合并连接:
使用单节点构成2-3-4树
操作后,在将结点11与原15结点位置交换,再将两结点合并连接:
使用单节点构成2-3-4树
结果为:
使用单节点构成2-3-4树

代码(附有操作方法)

class TreeMap2_3_4:
    BLANK=object()                  # in down_split method, substitute other node
    class Position:
        ''' position class'''
        def __init__(self,node,container):
            self._node=node
            self._container=container

        def element(self):
            ''' return value of position '''
            return self._node._value

        def key(self):
            return self._node._key

        def __eq__(self,other):
            return type(self)==type(other) and self._node is other._node
    #
    class _Node:
        ''' creat the link node,'''
        def __init__(self,k,v,before=None,after=None,parent=None,child=None):
            self._key=k
            self._value=v
            self._before=before
            self._after=after
            self._parent=parent
            self._child=child
        #--------------------------convennient the node------------------------        
        def __eq__(self,k):
            ''' return true, if k==self._key'''
            if type(k) ==int:
                return self._key==k
            elif isinstance(k,type(self)):
                return self._key==k._key
            
        def __nq__(self,k):
            return not self==k

        def __lt__(self,k):
            ''' return true if k < self._key'''
            if type(k) ==int:
                return self._key<k
            elif isinstance(k,type(self)):
                return self._key<k._key
        
        def __gt__(self,k):
            return not self<k and self!=k

        def __le__(self,k):
            return self<k or self == k

        def __ge__(self, k):
            return self>k or self ==k
    #--------------------------------
    def __init__(self):
        ''' root return the first node'''
        self._root=None
        self._size=0

    def _validate(self,p):
        ''' Return associated node, if position is valid.'''
        if not isinstance(p, self.Position):
            raise TypeError('p must be proper Position type')
        if p._container is not self:
            raise ValueError('p does not belong to this container')
        if p._node._parent is p._node:      # convention for deprecated nodes
            raise ValueError('p is no longer valid')
        return p._node

    def _make_position(self,node):
        ''' return position of node '''
        return self.Position(node,self) if node != None else None
    
    def _add_after(self,p,temp,head_node=None):
        ''' add a node after p,p is Position class;
            reconect node's after,before parent,without child.
        '''
        node=self._validate(p)
        # temp's before is node,after is node's after
        #,parent is node's parent
        temp._before=node
        temp._after=node._after
        temp._parent=node._parent
        node._after = temp
        if temp._after is not None:
            temp._after._before=temp
        if head_node is not None:
            while temp is not None:  # repoint child's parent,_add_beofre method can't repoint
                subnode = temp._child
                while subnode is not None:
                    subnode._parent = head_node
                    subnode = subnode._after
                temp = temp._after
        return self._make_position(temp)

    def _add_before(self,p,temp,head_node=None):
        ''' this method can only be used for p which before node is none;
            add a node before p,p is Position and head node;
            temp is a _Node;
            head_node is _Node class;
            reconnect node's child,parent'before and after.
        '''
        node=self._validate(p)
        # temp's before is node._before,after is node,
        #parent is node._parent
        if temp._before is not None and temp._child is None:  # in case 2.1 of down_split method
            temp._child=node._before
        else:
            temp._before=node._before
        temp._after=node
        temp._parent=node._parent
        node._before=temp
        parent=self.parent(p)
        if parent is None:
            self._root=temp
        else:
            parent=self._validate(parent)
            if parent._before is node:
                parent._before = temp
            if parent._child is node:
                parent._child = temp
        tempnode=temp
        if head_node is not None:
            while tempnode is not None:  # repoint child's parent,
                subnode = tempnode._child
                while subnode is not None:
                    subnode._parent = head_node
                    subnode = subnode._after
                tempnode = tempnode._after
        return self._make_position(temp)   # now temp is the head
    
    def _add(self,p,k,v,head):
        ''' add a node in a proper posiiton '''
        node=self._validate(p)
        temp=self._Node(k,v)
        self._size+=1
        if node < k:
            self._add_after(p,temp)
            self._up_split(head)
        else:
            self._up_split(self._add_before(p,temp,temp))

    def _search(self,k,head=None,node=None):
        ''' return the proper Position and head if chain's child is None;
            find begin of root if node is None
            head and node are _Node class
        '''
        if node is None:
            node=self._root
            head=node
        #print(node,k,self._root)
        if node>k:                  # recursion to node's before
            if node._before is None:# break the cursion if there is none child
                return self._make_position(node),self._make_position(head)
            return self._search(k,node._before,node._before)
        if node==k:                 # break the cursion
            return self._make_position(node),self._make_position(head)
        if node<k:                  # recursion to node's after
            if node._after is not None:     # if there is item after node
                if k<node._after:           # node<k<node._after
                    if node._child is None: # node is the last node
                        return self._make_position(node),self._make_position(head)
                    return self._search(k,node._child,node._child)
                else:                       # noke._after <k
                    return self._search(k,head,node._after)
            else:
                if node._child is None:     # if node is last Position
                    return self._make_position(node),self._make_position(head)
                return self._search(k,node._child,node._child)

    def _up_split(self,head):
        ''' head is a Position class'''        
        if self.is_filled(head):
            node=self._validate(head)
            mid=node._after._after  # split in to tree parts, (node,mid,p2)
            p2=mid._after           # p2 is the mid's child            
            parent=node._parent
            # combine the tree parts
            node._after._after=None
            p2._before=mid._child
            mid._child=p2
            p2._parent = parent      # if parent is None , p2._parent is mid
            temp=p2._before
            while temp is not None:# p2 became a head node ,repoint child and child._after
                temp._parent=p2
                temp=temp._after
            temp=p2._child
            while temp is not None:
                temp._parent = p2
                temp=temp._after
            # find the proper position for mid
            if parent is not None:  # if node isn't root
                parent=self._validate(self.parent(self._make_position(node)))# get the parent node
                if parent>mid:
                    if parent._before is node:# if mid add to the head ,the node and p2 's parent should be mid
                        self._add_before(self._make_position(parent),mid,mid)
                        node._parent=mid
                        node._after._parent=mid
                        return self._up_split(self._make_position(mid))
                    mid._before=parent._before
                    mid._before._after=mid
                    mid._after=parent
                    parent._before=mid
                    mid._parent=parent._parent                                                
                if parent<mid:
                    self._add_after(self._make_position(parent),mid)
                return self._up_split(self._make_position(node._parent))# Prevent overflow from passing upwards
            else: # if node is root
                # make mid is the root
                self._root=mid
                mid._before=node
                mid._after=None
                mid._parent=None
                # the node and p2 's parent should be mid
                node._parent=mid
                node._after._parent=mid
                p2._parent=mid

    def _pop(self,p,head):
        # warrring pop need to be devided in to situations
        ''' cut all links related p;
            p is the Position;
            p._before will be p._after._before and the p._child need to be None
        '''
        node=self._validate(p)
        after=node._after
        if after is not None:     
            before=node._before
            self._pointer_repoint(self._make_position(node._after),p,head)
            after._before=before    # repoint node's after node, node._after._before node
        else:
            self._pointer_repoint(None,p,head)

        return self._make_position(node)

    def _replace(self,p,position,head):
        ''' substitue position for p and return position '''
        node=self._validate(p)
        p_node=self._validate(position)
        if p_node._parent is not node:
            node._parent=p_node._parent
        node._child=p_node._child
        node._before=p_node._before
        node._after=p_node._after
        self._pointer_repoint(p,position,head)
        return position

    def _pointer_repoint(self,p,position,head):
        ''' the pointer to position repoints p ;
            when p is root and p.after is not empty,let p.after be root
        '''
        if p is not None:                   # in case p is None,when _pop() method
            node=self._validate(p)
        else:
            node = None
        p_node=self._validate(position)
        if p_node is self._root:                # if position is root node
            self._root=node
        if position == head:                   # repoint node's child and parent
            parent=self._validate(self.parent(position)) if p_node._parent is not None else None
            # all of child repoint to node
            temp = p_node._before       # before fraction
            while temp is not None:
                temp._parent = node
                temp = temp._after
            temp_node = p_node      # child fraction
            while temp_node is not None:
                temp = temp_node._child
                while temp is not None:
                    temp._parent = node
                    temp = temp._after
                temp_node = temp_node._after
            if parent is not None:          # repoint parent's child
                if parent._before is p_node:
                    parent._before=node
                else:
                    parent._child=node
        else:                              # if node is not head
            p_node._before._after=node
        if p_node._after is not None:     # repoint node's after node, node._after._before node
            p_node._after._before =node
        p_node._parent=None
        p_node._after=None
        p_node._before=None
        p_node._child=None

    def _brother(self,p,r=True):
        ''' return p's brother node;
            if r is Flase,denote the method working for recursion;
        '''
        node=self._validate(p)
        parent=self._validate(self.parent(p))
        parent_h=node._parent
        if parent._before is node:      # get brother
            brother=parent._child
            brother_head=brother
        else:
            brother1=parent._before if parent is parent_h else parent._before._child
            brother_head =brother1
            while brother1._after is not None:
                brother1=brother1._after
            if r:
                brother2=parent._after._child if parent._after is not None else None
                if not self.is_singular(self._make_position(brother2)) and self.is_singular(self._make_position(brother_head)):# let len less node be brother
                    brother = brother2
                    brother_head=brother2
                else:
                    brother=brother1
            else:
                brother=brother1
        return self._make_position(brother),self._make_position(brother_head)

    def _down_split(self,position,r=True):
        ''' cut chain of position ;
            case 1 :
                    position's brother is not singular
            case 2 :
                    position's brother is singular
                    case 2.1 :
                        position's parent is singular  (this way need recursion)
                    case 2.2 :
                        position's parnet is not singual
        '''
        node = self._validate(position)
        parent=self._validate(self.parent(position))
        parent_h=node._parent           # parent_h is parent's head
        brother,brother_head=self._brother(position,r)
        brother=self._validate(brother)
        if not self.is_singular(brother_head) and r:        # case 1
            brother_parent=self.parent(brother_head)
            temp1=self._pop(self._make_position(brother),brother_head)
                # replace temp1 with parent
            if node>brother:        # there are different parents when different size relationship of brother and node
                temp2=self._replace(temp1,self._make_position(parent),self._make_position(parent_h))
            else:
                temp2 = self._replace(temp1, brother_parent, self._make_position(parent_h))
               # replace temp2 with position
            temp3=self._replace(temp2,position,position)
            return temp3
        else:                                       # if brother is singular,case 2
            if self.is_singular(self._make_position(parent_h)):              # case 2.1
                blank_node=self._Node(parent._key,TreeMap2_3_4.BLANK)
                blank=self._make_position(blank_node)
                temp1=self._replace(blank,self._make_position(parent),self._make_position(parent))   # replace parent Position
                self._replace(temp1,position,position)            # replace position with parent
                if brother>parent:
                    blank_node._before = None
                    self._add_before(self._make_position(brother),parent,parent)
                    brother_head = self._make_position(parent)
                    if blank_node<blank_node._parent:# Deal with the before and child value issues of blank nodes
                        blank_node._before,blank_node._child=blank_node._child,blank_node._before
                else:
                    blank_node._child=None
                    self._add_after(self._make_position(brother),parent,self._validate(brother_head))
                    if blank_node>blank_node._parent:# Deal with the before and child value issues of blank nodes
                        blank_node._before, blank_node._child = blank_node._child, blank_node._before
                if blank_node._parent is None:                  # if blank is root
                    blank_node._before=blank_node._child if blank_node._child is not None else blank_node._before   # incase pop the node
                    blank_node._child=None
                    self._pop(blank,blank)
                    self._root=self._validate(brother_head) if self._validate(brother_head)<parent else parent
                    return self.root()
                # in case node is filled
                if self.is_filled(brother_head):
                    blank_node._before, blank_node._child = blank_node._child, blank_node._before
                    self._up_split(brother_head)
                    if parent<brother and blank_node._before is None:      # let new node be the _before of blank_node
                        blank_node._before=blank_node._child
                    blank_head=blank if blank_node<brother else self._make_position(blank_node._before)
                    self._pop(blank,blank_head)
                    return
                return self._down_split(blank,False)
            else:                                # if parent is not sigular ,case 2.2
                TEMP=self._make_position(self._Node(TreeMap2_3_4.BLANK,TreeMap2_3_4.BLANK))    # TEMP  uesed to repalce parent node
                self._replace(TEMP,self._make_position(parent),self._make_position(parent_h))  # parent Position
                res=self._replace(self._make_position(parent),position,position)               # position Position
                if brother > parent:        # add the older parent to brother
                    self._add_before(self._make_position(brother),parent,parent)
                    brother_head=self._make_position(parent)

                else:
                    self._add_after(self._make_position(brother),parent,self._validate(brother_head))
                if parent_h is parent:              # delete temp
                    if parent<brother:              # let new node be the left node of TEMP
                        TEMP._node._before=TEMP._node._child  # for _pop mtehod
                    TEMP._node._child=None          # let parent._before be parent._after._before for the pop method
                    parent_h=TEMP
                else:
                    parent_h=self._make_position(parent_h)
                self._pop(TEMP,parent_h)
                self._up_split(brother_head)
                return self._make_position(res)

    def _subnode(self,p,head):
        ''' find the subnode which should lt p of p  '''
        node = self._validate(p)
        if p == head:
            temp=node._before
        else:
            temp=node._before._child
        head=temp
        if temp is not None:
            while temp._after is not None or temp._child is not None:
                while temp._after is not None:
                    temp = temp._after
                if temp._child is not None:
                    temp=temp._child
                    head=temp
            return self._make_position(temp),self._make_position(head)
        else:
            return None,None

    def _before(self,p,head):
        ''' p is position ,head is p's head and a position;
            return position and head,position less than p 
        '''
        node=self._validate(p)   # find a proper subtree to search
        if node._before is None:   # node is leaf node
            if node._parent is None:                         # if p is the root node
                return None,None
            head=node._parent
            temp=self._validate(self.parent(p))
            while temp._before is node: # looking up to the top, find the before the node
                node=temp
                head=temp._parent
                temp=self._validate(self.parent(self._make_position(temp)))
                if temp is None:                            # if p is the leftmost node
                    return None,None
            if temp._before is not node:
                return self._make_position(temp),self._make_position(head)
        else:
            temp=node._before         # temp is the target node
            if p == head :         # if p is not head node
                return self._search(node._key, temp, temp)
            elif temp._child is not None:
                temp=temp._child
                return self._search(node._key, temp, temp)
            else:
                return self._make_position(temp),head


    def _next(self,p,head):
        ''' p is position ,head is p's head and head is position
             return position and head,position great than p
        '''
        node=self._validate(p)
        if node._child is not None:
            return self._search(node._key,node._child,node._child)
        if node._after is not None:
            return self._make_position(node._after),head
        temp=self._validate(self.parent(head))     # parent's child or before node is head
        head=self._make_position(node._parent)                          # get the parent 's head
        while temp<=node:                       # lookup the parent's node
            if temp._after is not None:         # if the parent has after node to return it, else travel to the top of the tree
                return self._make_position(temp._after),head
            head,temp=self._make_position(temp._parent),self._validate(self.parent(head))
        return self._make_position(temp), head

    def _generate(self,p,head):
        ''' recuisively yield _Node;
            n,head are class _Node;
            if return whole tree,p and head should convey both self._root.
        '''
        if p is None:
            return
        if p is head:
            for i in self._generate(p._before,p._before):
                yield  i
        yield self._make_position(p)
        for i in self._generate(p._child,p._child):
            yield i
        for i in self._generate(p._after,head):
            yield i

    def _get_head(self,n):
        ''' n is a Position, returning a node that is a Position '''
        n=self._validate(n)
        if n._child is not None:
            return self._make_position(n._child._parent)
        else:
            while n._before is not None:
                n=n._before
            return self._make_position(n)
            
    def __len__(self):
        return self._size
    
    def __setitem__(self,k,v):
        if len(self)==0:
            self._root=self._Node(k,v)
            self._size+=1
            return
        node,head=self._search(k)   # get the position and head
        if node.key()==k:
            node._node._value=v
        else:
            self._add(node,k,v,head)

    def __delitem__(self,k):
        position,head=self._search(k)           # delete node
        self._size-=1
        if position.key() !=k:
            raise KeyError('key warring')
        subs,subs_head=self._subnode(position,head)
        if subs is not None:                # dispose the position
            if self.is_singular(subs_head):
                self._down_split(subs)
                if self._validate(position)._parent is not None:    # in case head is changed,research position
                    t,head=self._search(position.element(),self._validate(position)._parent,self._validate(position)._parent)
                else :
                    t,head=position, self.root()
            else:
                self._pop(subs,subs_head)
            return self._replace(subs, position, head)
        else:
            if self.root()==position:       # if tree only has root node
                self._pop(position,position)
                self._size=0
                return
            else:
                if self.is_singular(head):  # if position is a leaf node , a head
                    return self._down_split(position)
                else:
                    return self._pop(position,head)
    
    def __getitem__(self, k):
        ''' return value of Position which key ==k,
            raise KeyError if k not find
         '''
        p,head=self._search(k)
        if p.key()==k:
            return p.element()
        else:
            raise KeyError('invalid key')

    def __contains__(self, k):
        p,head=self._search(k)
        if p.key()==k:
            return True
        else:
            return False

    def __iter__(self):
        for i in self._generate(self._root,self._root):
            yield i.element()

    def get(self, k, d):
        ''' if k is found return k.element else return d'''
        p,head=self._search(k)
        return p.element() if p.key()==k else d

    def is_filled(self,head):
        ''' return True, If the head is connected to two nodes'''
        head=self._validate(head)
        n=1
        while head._after is not None:
            head=head._after
            n+=1
        return n==4         # 4 is the  maxinum

    def is_singular(self,head):
        if head is None:
            return True        
        node=self._validate(head)
        return node._after is None

    def root(self):
        return self._make_position(self._root)

    def parent(self,p):
        ''' find p's parent position;
            p have to be  a head node.
        '''
        node=self._validate(p)
        parent=node._parent
        if parent is None:
            return None
        while not ( parent._before is node or parent._child is node):   # may
            parent=parent._after            
        return self._make_position(parent)

    def items(self):
        return [(i.key(),i.element()) for i in self._generate(self._root,self._root)]
    
    def pop(self,k,d=None):
        if d is None:
            raise KeyError('d have be not None')
        try:
            self.__delitem__(k)
        except KeyError:
            return d

    def popitem(self):
        import random
        seed=random.randint(0,len(self))                            
        for i in self._generate(self._root,self._root):
            if seed == 0:
                break           
            seed-=1
        self.__delitem__(i.key())
        return (i.key(),i.element())
    
    def setdefault(self,k,d):
        if len(self)==0:
            self._root=self._Node(k,d)
            self._size+=1
            return
        node,head=self._search(k)   # get the position and head
        if node.key()==k:
            return node.element()
        else:
            self._add(node,k,d,head)

# 11.64
    def find_min(self):
        ''' return first node of _generate'''
        temp=next(self._generate(self._root,self._root))
        return temp.key(),temp.element()
    
    def find_max(self):
        ''' find the last and rightmost node'''
        temp=self._root
        while temp._after is not None:
            temp=temp._after
        while temp._child is not None:
            temp=temp._child
            while temp._after is not None:
                temp=temp._after
        return temp._key,temp._value
        
    def find_lt(self,k):
        p,h=self._search(k)
        if p.key()==k:
            p,h=self._before(p,h)
        return p.key(),p.element()
    
    def find_le(self,k):
        p,h=self._search(k)
        return p.key(),p.element()
    
    def find_gt(self,k):
        p,h=self._search(k)
        p,h=self._next(p,h)
        return p.key(),p.element()
            
    def find_ge(self,k):
        p,h=self._search(k)
        if p.key()!=k:
            p,h=self._next(p,h)
        return p.key(),p.element()

    def find_range(self,start,stop=None):
        ''' start and stop is key '''
        if stop==None:
            stop=start
            start=self.first().key()    # define the initial number of start
        if stop < start or stop>len(self):
            raise IndexError('parameter is invalid')
        nex,h=self._search(start)    # find the first node
        while 1:            # get the next node in cycles
            yield nex.element()
            if nex.key()< stop-1:
                nex,h=self._next(nex,h)
            else:
                break

    def reversed(self):
        ''' return k all of the tree that reversed iter '''
        walk=self.last()
        head=self._get_head(walk)
        yield walk.element()
        for i in range(len(self)-1):
            walk,head=self._before(walk,head)
            yield walk.element()

    def first(self):
        ''' finding the mininum node ,return it's Position'''
        walk=self._root
        while walk._before is not None:
            walk=walk._before
        return self._make_position(walk)
    
    def last(self):
        ''' finding the maxnium node ,return it's Position'''
        walk=self._root
        while 1:                        # find the node which is the max k.
            while walk._after is not None:
                walk=walk._after
            if walk._child is not None:
                walk=walk._child
                head=walk
            else:
                break
        return self._make_position(walk)
        
    def before(self,p):
        ''' p is a Position,return a Position'''
        head=self._get_head(p)
        po,he=self._before(p,head)
        return po
        
    def after(self,p):
        ''' p is a Position, return a Position'''
        head=self._get_head(p)
        po,he=self._next(p,head)
        return po

    def find_position(self,k):
        ''' if k in the tree return a Position that belong k, else raise Error'''
        p,h=self._search(k)
        if p.key()==k:
            return p
        else:
            raise KeyError('invalid key')
        
def text63(o=100):
    t = TreeMap2_3_4()
#----------------del test
    for i in range(o):
        t[i]=str(i)+'#'
    for i in range(o):
        del t[i]
    print('order done')
    for i in range(o):
        t[i]=str(i)+'#'
    for i in range(o-1,-1,-1):
         # print(i)
        del t[i]
    print('reverse order done')
 #------------ test del from the midst
    for i in range(o):
        t[i]=str(i)+'#'
    for i in range(o//2,-1,-1):
        # print(i)
        del t[i]
    print('midst previous done')
    for i in range(o//2+1,0):
        # print(i)
        del t[i]
    print('midst afterwards done')
    print(3 in t)
    print(t.get(-3,'d'))
    print(t.items())
    #del t
    #print(t)
    print(iter(t))
    print(t.pop(-3,'test pop'))
    print(t.popitem())
    print(t.setdefault(-3,'-3#'),t[-3])
#text63(180)

# 11.64  见11.63的类中
def text64():
    t = TreeMap2_3_4()
    for i in range(1000):
        t[i]=str(i)+"#"
    print(t.find_min())
    print(t.find_max())
    print(t.find_lt(500))
    print(t.find_le(500))
    print(t.find_gt(500)) 
    print(t.find_ge(500))
    for i in t.find_range(1000):
        print(i)
    for i in t.reversed():
        print(i)
#text64()

# 11.65 见11.53的类中
def text65():
    t=TreeMap2_3_4()
    for i in range(1000):
        t[i]=str(i)+'#'
    a=t.first()
    b=t.last()
    print(a.element(),t.after(a).element())
    print(b.element(),t.before(b).element())
    print(t.find_position(999).element())
    print(t.find_position(333).element())
#text65()
上一篇:Java内存模型相关


下一篇:JMM java内存模型 1.并发的关键,2.jmm内存模型,3.指令重排 4、happens-before