mirror of
https://github.com/heqin-zhu/algorithm.git
synced 2024-03-22 13:30:46 +08:00
Update bloomFilter, cantor, redblackTrue,matrix_chain_multiply
This commit is contained in:
parent
0c08851597
commit
d1cf579a2b
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,5 +1,6 @@
|
||||||
.*
|
.*
|
||||||
*.o
|
*.o
|
||||||
*.exe
|
*.exe
|
||||||
__pycache__/**
|
__pycache__
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
*.out
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Algorithm and Data Structures
|
# Algorithm
|
||||||
>Notes and codes for learning algorithm and data structures :smiley:
|
>Notes and codes for learning algorithm and data structures :smiley:
|
||||||
|
|
||||||
Some pictures and ideas are from `<<Introduction to Algotithm>>
|
Some pictures and ideas are from `<<Introduction to Algotithm>>
|
||||||
|
|
122
dataStructure/intervalTree.py
Normal file
122
dataStructure/intervalTree.py
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
from redBlackTree import redBlackTree
|
||||||
|
|
||||||
|
from functools import total_ordering
|
||||||
|
|
||||||
|
@total_ordering
|
||||||
|
class node:
|
||||||
|
def __init__(self,low,high,left=None,right=None,isBlack=False):
|
||||||
|
self.val = low # self.val is the low
|
||||||
|
self.high = high
|
||||||
|
self.max = high
|
||||||
|
self.left = left
|
||||||
|
self.right = right
|
||||||
|
self.parent=None
|
||||||
|
self.isBlack = isBlack
|
||||||
|
def __lt__(self,nd):
|
||||||
|
return self.val < nd.val
|
||||||
|
def __eq__(self,nd):
|
||||||
|
return nd is not None and self.val == nd.val
|
||||||
|
def setChild(self,nd,isLeft = True):
|
||||||
|
if isLeft: self.left = nd
|
||||||
|
else: self.right = nd
|
||||||
|
if nd is not None: nd.parent = self
|
||||||
|
def getChild(self,isLeft):
|
||||||
|
if isLeft: return self.left
|
||||||
|
else: return self.right
|
||||||
|
def __bool__(self):
|
||||||
|
return self.val is not None
|
||||||
|
def __str__(self):
|
||||||
|
color = 'B' if self.isBlack else 'R'
|
||||||
|
return f'{color}[{self.val},{self.high}]-{self.max}'
|
||||||
|
def __repr__(self):
|
||||||
|
return f'intervalNode({self.val},{self.high},{self.max},isBlack={self.isBlack})'
|
||||||
|
def overlap(self,low,high):
|
||||||
|
return self.val<=high and self.high>=low
|
||||||
|
def setMax(self):
|
||||||
|
l = 0 if self.left is None else self.left.max
|
||||||
|
r = 0 if self.right is None else self.right.max
|
||||||
|
self.max = max(self.high, l, r)
|
||||||
|
return self.max
|
||||||
|
|
||||||
|
class intervalTree(redBlackTree):
|
||||||
|
def search(self,low,high):
|
||||||
|
nd = self.root
|
||||||
|
while nd is not None and not nd.overlap(low,high):
|
||||||
|
if nd.left is not None and nd.left.max>=low:
|
||||||
|
nd = nd.left
|
||||||
|
else:nd = nd.right
|
||||||
|
return nd
|
||||||
|
def insert(self,nd):
|
||||||
|
super(intervalTree,self).insert(nd)
|
||||||
|
while nd is not None:
|
||||||
|
nd.setMax()
|
||||||
|
nd = nd.parent
|
||||||
|
def delete(self,val):
|
||||||
|
nd = self.find(val)
|
||||||
|
if nd is not None:
|
||||||
|
nd.max = 0
|
||||||
|
tmp = nd.parent
|
||||||
|
while tmp is not None:
|
||||||
|
tmp.setMax()
|
||||||
|
tmp = tmp.parent
|
||||||
|
super(intervalTree,self).delete(val)
|
||||||
|
def rotate(self,prt,chd):
|
||||||
|
'''rotate prt, and return new prt, namyly the original chd'''
|
||||||
|
super(intervalTree,self).rotate(prt,chd)
|
||||||
|
prt.setMax()
|
||||||
|
chd.setMax()
|
||||||
|
def copyNode(self,src,des):
|
||||||
|
des.val = src.val
|
||||||
|
des.high = src.high
|
||||||
|
des.setMax()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
from random import randint, shuffle
|
||||||
|
def genNum(n =10,upper=10):
|
||||||
|
nums ={}
|
||||||
|
for i in range(n):
|
||||||
|
while 1:
|
||||||
|
d = randint(0,100)
|
||||||
|
if d not in nums:
|
||||||
|
nums[d] = (d,randint(d,d+upper))
|
||||||
|
break
|
||||||
|
return nums.values()
|
||||||
|
|
||||||
|
def buildTree(n=10,nums=None,visitor=None):
|
||||||
|
if nums is None or nums ==[]: nums = genNum(n)
|
||||||
|
tree = intervalTree()
|
||||||
|
print(f'build a red-black tree using {nums}')
|
||||||
|
for i in nums:
|
||||||
|
tree.insert(node(*i))
|
||||||
|
if visitor:
|
||||||
|
visitor(tree,i)
|
||||||
|
return tree,nums
|
||||||
|
def testInsert(nums=None):
|
||||||
|
def visitor(t,val):
|
||||||
|
print('inserting', val)
|
||||||
|
print(t)
|
||||||
|
tree,nums = buildTree(visitor = visitor,nums=nums)
|
||||||
|
print('-'*5+ 'in-order visit' + '-'*5)
|
||||||
|
for i,j in enumerate(tree.sort()):
|
||||||
|
print(f'{i+1}: {j}')
|
||||||
|
|
||||||
|
def testSuc(nums=None):
|
||||||
|
tree,nums = buildTree(nums=nums)
|
||||||
|
for i in tree.sort():
|
||||||
|
print(f'{i}\'s suc is {tree.getSuccessor(i)}')
|
||||||
|
|
||||||
|
def testDelete(nums=None):
|
||||||
|
tree,nums = buildTree(nums = nums)
|
||||||
|
print(tree)
|
||||||
|
for i in nums:
|
||||||
|
print(f'deleting {i}')
|
||||||
|
tree.delete(i[0])
|
||||||
|
print(tree)
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
lst = [(0,3),(5,8),(6,10),(26,26),(25,30),(8,9),(19,20),(15,23),(16,21),(17,19)]
|
||||||
|
lst = None
|
||||||
|
#testSuc(lst)
|
||||||
|
#testInsert(lst)
|
||||||
|
testDelete(lst)
|
|
@ -9,18 +9,6 @@
|
||||||
# Description:
|
# Description:
|
||||||
#########################################################################
|
#########################################################################
|
||||||
'''
|
'''
|
||||||
|
|
||||||
'''
|
|
||||||
#########################################################################
|
|
||||||
# File : redBlackTree.py
|
|
||||||
# Author: mbinary
|
|
||||||
# Mail: zhuheqin1@gmail.com
|
|
||||||
# Blog: https://mbinary.coding.me
|
|
||||||
# Github: https://github.com/mbinary
|
|
||||||
# Created Time: 2018-07-12 20:34
|
|
||||||
# Description:
|
|
||||||
#########################################################################
|
|
||||||
'''
|
|
||||||
from functools import total_ordering
|
from functools import total_ordering
|
||||||
from random import randint, shuffle
|
from random import randint, shuffle
|
||||||
|
|
||||||
|
@ -30,14 +18,17 @@ class node:
|
||||||
self.val =val
|
self.val =val
|
||||||
self.left = left
|
self.left = left
|
||||||
self.right = right
|
self.right = right
|
||||||
|
self.parent= None
|
||||||
self.isBlack = isBlack
|
self.isBlack = isBlack
|
||||||
def __lt__(self,nd):
|
def __lt__(self,nd):
|
||||||
return self.val < nd.val
|
return self.val < nd.val
|
||||||
def __eq__(self,nd):
|
def __eq__(self,nd):
|
||||||
return nd is not None and self.val == nd.val
|
return nd is not None and self.val == nd.val
|
||||||
def setChild(self,nd,isLeft = True):
|
def setChild(self,nd,isLeft):
|
||||||
if isLeft: self.left = nd
|
if isLeft: self.left = nd
|
||||||
else: self.right = nd
|
else: self.right = nd
|
||||||
|
if nd is not None: nd.parent = self
|
||||||
|
|
||||||
def getChild(self,isLeft):
|
def getChild(self,isLeft):
|
||||||
if isLeft: return self.left
|
if isLeft: return self.left
|
||||||
else: return self.right
|
else: return self.right
|
||||||
|
@ -45,7 +36,8 @@ class node:
|
||||||
return self.val is not None
|
return self.val is not None
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
color = 'B' if self.isBlack else 'R'
|
color = 'B' if self.isBlack else 'R'
|
||||||
return f'{color}-{self.val:}'
|
val = '-' if self.parent==None else self.parent.val
|
||||||
|
return f'{color}-{self.val}'
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f'node({self.val},isBlack={self.isBlack})'
|
return f'node({self.val},isBlack={self.isBlack})'
|
||||||
class redBlackTree:
|
class redBlackTree:
|
||||||
|
@ -63,6 +55,159 @@ class redBlackTree:
|
||||||
if isBlack is None or isBlack:
|
if isBlack is None or isBlack:
|
||||||
nd.isBlack = True
|
nd.isBlack = True
|
||||||
else:nd.isBlack = False
|
else:nd.isBlack = False
|
||||||
|
def setRoot(self,nd):
|
||||||
|
if nd is not None: nd.parent=None
|
||||||
|
self.root= nd
|
||||||
|
def find(self,val):
|
||||||
|
nd = self.root
|
||||||
|
while nd:
|
||||||
|
if nd.val ==val:
|
||||||
|
return nd
|
||||||
|
else:
|
||||||
|
nd = nd.getChild(nd.val>val)
|
||||||
|
def getSuccessor(self,nd):
|
||||||
|
if nd:
|
||||||
|
if nd.right:
|
||||||
|
nd = nd.right
|
||||||
|
while nd.left:
|
||||||
|
nd = nd.left
|
||||||
|
return nd
|
||||||
|
else:
|
||||||
|
while nd.parent is not None and nd.parent.right is nd:
|
||||||
|
nd = nd.parent
|
||||||
|
return None if nd is self.root else nd.parent
|
||||||
|
def rotate(self,prt,chd):
|
||||||
|
'''rotate prt with the center of chd'''
|
||||||
|
if self.root is prt:
|
||||||
|
self.setRoot(chd)
|
||||||
|
else:
|
||||||
|
prt.parent.setChild(chd, prt.parent.left is prt)
|
||||||
|
isLeftChd = prt.left is chd
|
||||||
|
prt.setChild(chd.getChild(not isLeftChd), isLeftChd)
|
||||||
|
chd.setChild(prt,not isLeftChd)
|
||||||
|
|
||||||
|
def insert(self,nd):
|
||||||
|
if nd.isBlack: nd.isBlack = False
|
||||||
|
|
||||||
|
if self.root is None:
|
||||||
|
self.setRoot(nd)
|
||||||
|
self.root.isBlack = True
|
||||||
|
else:
|
||||||
|
parent = self.root
|
||||||
|
while parent:
|
||||||
|
if parent == nd : return None
|
||||||
|
isLeft = parent > nd
|
||||||
|
chd = parent.getChild(isLeft)
|
||||||
|
if chd is None:
|
||||||
|
parent.setChild(nd,isLeft)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
parent = chd
|
||||||
|
self.fixUpInsert(parent,nd)
|
||||||
|
def fixUpInsert(self,parent,nd):
|
||||||
|
''' adjust color and level, there are two red nodes: the new one and its parent'''
|
||||||
|
while not self.checkBlack(parent):
|
||||||
|
grand = parent.parent
|
||||||
|
isLeftPrt = grand.left is parent
|
||||||
|
uncle = grand.getChild(not isLeftPrt)
|
||||||
|
if not self.checkBlack(uncle):
|
||||||
|
# case 1: new node's uncle is red
|
||||||
|
self.setBlack(grand, False)
|
||||||
|
self.setBlack(grand.left, True)
|
||||||
|
self.setBlack(grand.right, True)
|
||||||
|
nd = grand
|
||||||
|
parent = nd.parent
|
||||||
|
else:
|
||||||
|
# case 2: new node's uncle is black(including nil leaf)
|
||||||
|
isLeftNode = parent.left is nd
|
||||||
|
if isLeftNode ^ isLeftPrt:
|
||||||
|
# case 2.1 the new node is inserted in left-right or right-left form
|
||||||
|
# grand grand
|
||||||
|
# parent or parent
|
||||||
|
# nd nd
|
||||||
|
self.rotate(parent,nd) #parent rotate
|
||||||
|
nd,parent = parent,nd
|
||||||
|
# case 3 (case 2.2) the new node is inserted in left-left or right-right form
|
||||||
|
# grand grand
|
||||||
|
# parent or parent
|
||||||
|
# nd nd
|
||||||
|
|
||||||
|
self.setBlack(grand, False)
|
||||||
|
self.setBlack(parent, True)
|
||||||
|
self.rotate(grand,parent)
|
||||||
|
self.setBlack(self.root,True)
|
||||||
|
|
||||||
|
def copyNode(self,src,des):
|
||||||
|
'''when deleting a node which has two kids,
|
||||||
|
copy its succesor's data to his position
|
||||||
|
data exclude left, right , isBlack
|
||||||
|
'''
|
||||||
|
des.val = src.val
|
||||||
|
def delete(self,val):
|
||||||
|
'''delete node in a binary search tree'''
|
||||||
|
if isinstance(val,node): val = val.val
|
||||||
|
nd = self.find(val)
|
||||||
|
if nd is None: return
|
||||||
|
self._delete(nd)
|
||||||
|
def _delete(self,nd):
|
||||||
|
y = None
|
||||||
|
if nd.left and nd.right:
|
||||||
|
y= self.getSuccessor(nd)
|
||||||
|
else:
|
||||||
|
y = nd
|
||||||
|
py = y.parent
|
||||||
|
x = y.left if y.left else y.right
|
||||||
|
if py is None:
|
||||||
|
self.setRoot(x)
|
||||||
|
else:
|
||||||
|
py.setChild(x,py.left is y)
|
||||||
|
if y != nd:
|
||||||
|
self.copyNode(y,nd)
|
||||||
|
if self.checkBlack(y): self.fixUpDel(py,x)
|
||||||
|
|
||||||
|
def fixUpDel(self,prt,chd):
|
||||||
|
''' adjust colors and rotate '''
|
||||||
|
while self.root != chd and self.checkBlack(chd):
|
||||||
|
isLeft =prt.left is chd
|
||||||
|
brother = prt.getChild(not isLeft)
|
||||||
|
# brother is black
|
||||||
|
lb = self.checkBlack(brother.getChild(isLeft))
|
||||||
|
rb = self.checkBlack(brother.getChild(not isLeft))
|
||||||
|
if not self.checkBlack(brother):
|
||||||
|
# case 1: brother is red. converted to case 2,3,4
|
||||||
|
|
||||||
|
self.setBlack(prt,False)
|
||||||
|
self.setBlack(brother,True)
|
||||||
|
self.rotate(prt,brother)
|
||||||
|
|
||||||
|
elif lb and rb:
|
||||||
|
# case 2: brother is black and two kids are black.
|
||||||
|
# conveted to the begin case
|
||||||
|
self.setBlack(brother,False)
|
||||||
|
chd = prt
|
||||||
|
prt= chd.parent
|
||||||
|
else:
|
||||||
|
if rb:
|
||||||
|
# case 3: brother is black and left kid is red and right child is black
|
||||||
|
# rotate bro to make g w wl wr in one line
|
||||||
|
# uncle's son is nephew, and niece for uncle's daughter
|
||||||
|
nephew = brother.getChild(isLeft)
|
||||||
|
self.setBlack(nephew,True)
|
||||||
|
self.setBlack(brother,False)
|
||||||
|
|
||||||
|
# brother (not isLeft) rotate
|
||||||
|
self.rotate(brother,nephew)
|
||||||
|
brother = nephew
|
||||||
|
|
||||||
|
# case 4: brother is black and right child is red
|
||||||
|
brother.isBlack = prt.isBlack
|
||||||
|
self.setBlack(prt,True)
|
||||||
|
self.setBlack(brother.getChild(not isLeft),True)
|
||||||
|
|
||||||
|
self.rotate(prt,brother)
|
||||||
|
chd = self.root
|
||||||
|
self.setBlack(chd,True)
|
||||||
|
|
||||||
def sort(self,reverse = False):
|
def sort(self,reverse = False):
|
||||||
''' return a generator of sorted data'''
|
''' return a generator of sorted data'''
|
||||||
def inOrder(root):
|
def inOrder(root):
|
||||||
|
@ -77,184 +222,6 @@ class redBlackTree:
|
||||||
else:
|
else:
|
||||||
yield from inOrder(root.right)
|
yield from inOrder(root.right)
|
||||||
yield from inOrder(self.root)
|
yield from inOrder(self.root)
|
||||||
def getParent(self,chd):
|
|
||||||
'''note that use is to find real node when different nodes have euqiv val'''
|
|
||||||
if self.root is chd:return None
|
|
||||||
nd = self.root
|
|
||||||
while nd:
|
|
||||||
if nd>chd and nd.left is not None:
|
|
||||||
if nd.left is chd: return nd
|
|
||||||
else: nd = nd.left
|
|
||||||
elif nd<chd and nd.right is not None:
|
|
||||||
if nd.right is chd: return nd
|
|
||||||
else: nd = nd.right
|
|
||||||
def find(self,val):
|
|
||||||
nd = self.root
|
|
||||||
while nd:
|
|
||||||
if nd.val ==val:
|
|
||||||
return nd
|
|
||||||
elif nd.val>val:
|
|
||||||
nd = nd.left
|
|
||||||
else:
|
|
||||||
nd = nd.right
|
|
||||||
def getSuccessor(self,nd):
|
|
||||||
if nd:
|
|
||||||
if nd.right:
|
|
||||||
nd = nd.right
|
|
||||||
while nd.left:
|
|
||||||
nd = nd.left
|
|
||||||
return nd
|
|
||||||
else:return self.getParent(nd)
|
|
||||||
def transferParent(self,origin,new):
|
|
||||||
if origin is self.root:
|
|
||||||
self.root = new
|
|
||||||
else:
|
|
||||||
prt = self.getParent(origin)
|
|
||||||
prt.setChild(new, prt.left is origin)
|
|
||||||
|
|
||||||
def insert(self,nd):
|
|
||||||
if not isinstance(nd,node):
|
|
||||||
nd = node(nd)
|
|
||||||
elif nd.isBlack: nd.isBlack = False
|
|
||||||
|
|
||||||
if self.root is None:
|
|
||||||
self.root = nd
|
|
||||||
self.root.isBlack = True
|
|
||||||
else:
|
|
||||||
parent = self.root
|
|
||||||
while parent:
|
|
||||||
if parent == nd : return None
|
|
||||||
if parent>nd:
|
|
||||||
if parent.left :
|
|
||||||
parent = parent.left
|
|
||||||
else:
|
|
||||||
parent.left = nd
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if parent.right:
|
|
||||||
parent = parent.right
|
|
||||||
else:
|
|
||||||
parent.right = nd
|
|
||||||
break
|
|
||||||
self.fixUpInsert(parent,nd)
|
|
||||||
def fixUpInsert(self,parent,nd):
|
|
||||||
''' adjust color and level, there are two red nodes: the new one and its parent'''
|
|
||||||
while not self.checkBlack(parent):
|
|
||||||
grand = self.getParent(parent)
|
|
||||||
isLeftPrt = grand.left is parent
|
|
||||||
uncle = grand.getChild(not isLeftPrt)
|
|
||||||
if not self.checkBlack(uncle):
|
|
||||||
# case 1: new node's uncle is red
|
|
||||||
self.setBlack(grand, False)
|
|
||||||
self.setBlack(grand.left, True)
|
|
||||||
self.setBlack(grand.right, True)
|
|
||||||
nd = grand
|
|
||||||
parent = self.getParent(nd)
|
|
||||||
else:
|
|
||||||
# case 2: new node's uncle is black(including nil leaf)
|
|
||||||
isLeftNode = parent.left is nd
|
|
||||||
if isLeftNode ^ isLeftPrt:
|
|
||||||
# case 2.1 the new node is inserted in left-right or right-left form
|
|
||||||
# grand grand
|
|
||||||
# parent or parent
|
|
||||||
# nd nd
|
|
||||||
parent.setChild(nd.getChild(isLeftPrt),not isLeftPrt)
|
|
||||||
nd.setChild(parent,isLeftPrt)
|
|
||||||
grand.setChild(nd,isLeftPrt)
|
|
||||||
nd,parent = parent,nd
|
|
||||||
# case 2.2 the new node is inserted in left-left or right-right form
|
|
||||||
# grand grand
|
|
||||||
# parent or parent
|
|
||||||
# nd nd
|
|
||||||
grand.setChild(parent.getChild(not isLeftPrt),isLeftPrt)
|
|
||||||
parent.setChild(grand,not isLeftPrt)
|
|
||||||
self.setBlack(grand, False)
|
|
||||||
self.setBlack(parent, True)
|
|
||||||
self.transferParent(grand,parent)
|
|
||||||
self.setBlack(self.root,True)
|
|
||||||
|
|
||||||
def copyNode(self,src,des):
|
|
||||||
'''when deleting a node which has two kids,
|
|
||||||
copy its succesor's data to his position
|
|
||||||
data exclude left, right , isBlack
|
|
||||||
'''
|
|
||||||
des.val = src.val
|
|
||||||
def delete(self,nd):
|
|
||||||
'''delete node in a binary search tree'''
|
|
||||||
if not isinstance(nd,node):
|
|
||||||
nd = self.find(nd)
|
|
||||||
if nd is None: return
|
|
||||||
y = None
|
|
||||||
if nd.left and nd.right:
|
|
||||||
y= self.getSuccessor(nd)
|
|
||||||
else:
|
|
||||||
y = nd
|
|
||||||
py = self.getParent(y)
|
|
||||||
x = y.left if y.left else y.right
|
|
||||||
if py is None:
|
|
||||||
self.root = x
|
|
||||||
elif y is py.left:
|
|
||||||
py.left = x
|
|
||||||
else:
|
|
||||||
py.right = x
|
|
||||||
if y != nd:
|
|
||||||
self.copyNode(y,nd)
|
|
||||||
|
|
||||||
if self.checkBlack(y): self.fixUpDel(py,x)
|
|
||||||
|
|
||||||
|
|
||||||
def fixUpDel(self,prt,chd):
|
|
||||||
''' adjust colors and rotate '''
|
|
||||||
while self.root != chd and self.checkBlack(chd):
|
|
||||||
isLeft = prt.left is chd
|
|
||||||
brother = prt.getChild(not isLeft)
|
|
||||||
# brother is black
|
|
||||||
lb = self.checkBlack(brother.getChild(isLeft))
|
|
||||||
rb = self.checkBlack(brother.getChild(not isLeft))
|
|
||||||
if not self.checkBlack(brother):
|
|
||||||
# case 1: brother is red. converted to case 2,3,4
|
|
||||||
# prt (isLeft) rotate
|
|
||||||
prt.setChild(brother.getChild(isLeft), not isLeft)
|
|
||||||
brother.setChild(prt, isLeft)
|
|
||||||
|
|
||||||
self.setBlack(prt,False)
|
|
||||||
self.setBlack(brother,True)
|
|
||||||
|
|
||||||
self.transferParent(prt,brother)
|
|
||||||
elif lb and rb:
|
|
||||||
# case 2: brother is black and two kids are black.
|
|
||||||
# conveted to the begin case
|
|
||||||
self.setBlack(brother,False)
|
|
||||||
chd = prt
|
|
||||||
prt = self.getParent(chd)
|
|
||||||
else:
|
|
||||||
if rb:
|
|
||||||
# case 3: brother is black and left kid is red and right child is black
|
|
||||||
# uncle's son is nephew, and niece for uncle's daughter
|
|
||||||
nephew = brother.getChild(isLeft)
|
|
||||||
self.setBlack(nephew,True)
|
|
||||||
self.setBlack(brother,False)
|
|
||||||
|
|
||||||
# brother (not isLeft) rotate
|
|
||||||
prt.setChild(nephew,not isLeft)
|
|
||||||
brother.setChild(nephew.getChild(not isLeft),isLeft)
|
|
||||||
nephew.setChild(brother, not isLeft)
|
|
||||||
brother = nephew
|
|
||||||
|
|
||||||
# case 4: brother is black and right child is red
|
|
||||||
brother.isBlack = prt.isBlack
|
|
||||||
self.setBlack(prt,True)
|
|
||||||
self.setBlack(brother.getChild(not isLeft),True)
|
|
||||||
|
|
||||||
# prt left rotate
|
|
||||||
prt.setChild(brother.getChild(isLeft),not isLeft)
|
|
||||||
brother.setChild(prt,isLeft)
|
|
||||||
|
|
||||||
self.transferParent(prt,brother)
|
|
||||||
|
|
||||||
chd = self.root
|
|
||||||
self.setBlack(chd,True)
|
|
||||||
|
|
||||||
|
|
||||||
def display(self):
|
def display(self):
|
||||||
def getHeight(nd):
|
def getHeight(nd):
|
||||||
|
@ -280,7 +247,7 @@ class redBlackTree:
|
||||||
lst +=[None,None]
|
lst +=[None,None]
|
||||||
return level
|
return level
|
||||||
def addBlank(lines):
|
def addBlank(lines):
|
||||||
width = 5
|
width = 1+len(str(self.root))
|
||||||
sep = ' '*width
|
sep = ' '*width
|
||||||
n = len(lines)
|
n = len(lines)
|
||||||
for i,oneline in enumerate(lines):
|
for i,oneline in enumerate(lines):
|
||||||
|
@ -295,10 +262,10 @@ class redBlackTree:
|
||||||
lines = levelVisit(self.root)
|
lines = levelVisit(self.root)
|
||||||
lines = addBlank(lines)
|
lines = addBlank(lines)
|
||||||
li = [''.join(line) for line in lines]
|
li = [''.join(line) for line in lines]
|
||||||
li.insert(0,'red-black-tree'.rjust(48,'-') + '-'*33)
|
length = 10 if li==[] else max(len(i) for i in li)//2
|
||||||
li.append('end'.rjust(42,'-')+'-'*39+'\n')
|
begin ='\n'+ 'red-black-tree'.rjust(length+14,'-') + '-'*(length)
|
||||||
return '\n'.join(li)
|
end = '-'*(length*2+14)+'\n'
|
||||||
|
return '\n'.join([begin,*li,end])
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.display()
|
return self.display()
|
||||||
|
|
||||||
|
@ -318,34 +285,35 @@ def buildTree(n=10,nums=None,visitor=None):
|
||||||
rbtree = redBlackTree()
|
rbtree = redBlackTree()
|
||||||
print(f'build a red-black tree using {nums}')
|
print(f'build a red-black tree using {nums}')
|
||||||
for i in nums:
|
for i in nums:
|
||||||
rbtree.insert(i)
|
rbtree.insert(node(i))
|
||||||
if visitor:
|
if visitor:
|
||||||
visitor(rbtree)
|
visitor(rbtree,i)
|
||||||
return rbtree,nums
|
return rbtree,nums
|
||||||
def testInsert():
|
def testInsert(nums=None):
|
||||||
def visitor(t):
|
def visitor(t,val):
|
||||||
|
print('inserting', val)
|
||||||
print(t)
|
print(t)
|
||||||
rbtree,nums = buildTree(visitor = visitor)
|
rbtree,nums = buildTree(visitor = visitor,nums=nums)
|
||||||
print('-'*5+ 'in-order visit' + '-'*5)
|
print('-'*5+ 'in-order visit' + '-'*5)
|
||||||
for i,j in enumerate(rbtree.sort()):
|
for i,j in enumerate(rbtree.sort()):
|
||||||
print(f'{i+1}: {j}')
|
print(f'{i+1}: {j}')
|
||||||
|
|
||||||
def testSuc():
|
def testSuc(nums=None):
|
||||||
rbtree,nums = buildTree()
|
rbtree,nums = buildTree(nums=nums)
|
||||||
for i in rbtree.sort():
|
for i in rbtree.sort():
|
||||||
print(f'{i}\'s suc is {rbtree.getSuccessor(i)}')
|
print(f'{i}\'s suc is {rbtree.getSuccessor(i)}')
|
||||||
|
|
||||||
def testDelete():
|
def testDelete(nums=None):
|
||||||
#nums = [2,3,3,2,6,7,2,1]
|
|
||||||
nums = None
|
|
||||||
rbtree,nums = buildTree(nums = nums)
|
rbtree,nums = buildTree(nums = nums)
|
||||||
print(rbtree)
|
print(rbtree)
|
||||||
for i in nums:
|
for i in sorted(nums):
|
||||||
print(f'deleting {i}')
|
print(f'deleting {i}')
|
||||||
rbtree.delete(i)
|
rbtree.delete(i)
|
||||||
print(rbtree)
|
print(rbtree)
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__=='__main__':
|
||||||
#testSuc()
|
lst =[45, 30, 64, 36, 95, 38, 76, 34, 50, 1]
|
||||||
#testInsert()
|
lst = [0,3,5,6,26,25,8,19,15,16,17]
|
||||||
|
#testSuc(lst)
|
||||||
|
#testInsert(lst)
|
||||||
testDelete()
|
testDelete()
|
||||||
|
|
339
dataStructure/redBlackTree0.py
Normal file
339
dataStructure/redBlackTree0.py
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
''' mbinary
|
||||||
|
#########################################################################
|
||||||
|
# File : redBlackTree.py
|
||||||
|
# Author: mbinary
|
||||||
|
# Mail: zhuheqin1@gmail.com
|
||||||
|
# Blog: https://mbinary.coding.me
|
||||||
|
# Github: https://github.com/mbinary
|
||||||
|
# Created Time: 2018-07-14 16:15
|
||||||
|
# Description:
|
||||||
|
#########################################################################
|
||||||
|
'''
|
||||||
|
from functools import total_ordering
|
||||||
|
from random import randint, shuffle
|
||||||
|
|
||||||
|
@total_ordering
|
||||||
|
class node:
|
||||||
|
def __init__(self,val,left=None,right=None,isBlack=False):
|
||||||
|
self.val =val
|
||||||
|
self.left = left
|
||||||
|
self.right = right
|
||||||
|
self.isBlack = isBlack
|
||||||
|
def __lt__(self,nd):
|
||||||
|
return self.val < nd.val
|
||||||
|
def __eq__(self,nd):
|
||||||
|
return nd is not None and self.val == nd.val
|
||||||
|
def setChild(self,nd,isLeft):
|
||||||
|
if isLeft: self.left = nd
|
||||||
|
else: self.right = nd
|
||||||
|
def getChild(self,isLeft):
|
||||||
|
if isLeft: return self.left
|
||||||
|
else: return self.right
|
||||||
|
def __bool__(self):
|
||||||
|
return self.val is not None
|
||||||
|
def __str__(self):
|
||||||
|
color = 'B' if self.isBlack else 'R'
|
||||||
|
return f'{color}-{self.val}'
|
||||||
|
def __repr__(self):
|
||||||
|
return f'node({self.val},isBlack={self.isBlack})'
|
||||||
|
class redBlackTree:
|
||||||
|
def __init__(self,unique=False):
|
||||||
|
'''if unique is True, all node'vals are unique, else there may be equal vals'''
|
||||||
|
self.root = None
|
||||||
|
self.unique = unique
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def checkBlack(nd):
|
||||||
|
return nd is None or nd.isBlack
|
||||||
|
@staticmethod
|
||||||
|
def setBlack(nd,isBlack):
|
||||||
|
if nd is not None:
|
||||||
|
if isBlack is None or isBlack:
|
||||||
|
nd.isBlack = True
|
||||||
|
else:nd.isBlack = False
|
||||||
|
def getParent(self,chd):
|
||||||
|
'''note that use is to find real node when different nodes have euqiv val'''
|
||||||
|
if self.root is chd:return None
|
||||||
|
nd = self.root
|
||||||
|
while nd:
|
||||||
|
if nd>chd and nd.left is not None:
|
||||||
|
if nd.left is chd: return nd
|
||||||
|
else: nd = nd.left
|
||||||
|
elif nd<chd and nd.right is not None:
|
||||||
|
if nd.right is chd: return nd
|
||||||
|
else: nd = nd.right
|
||||||
|
def find(self,val):
|
||||||
|
nd = self.root
|
||||||
|
while nd:
|
||||||
|
if nd.val ==val:
|
||||||
|
return nd
|
||||||
|
else:
|
||||||
|
nd = nd.getChild(nd.val>val)
|
||||||
|
def getSuccessor(self,nd):
|
||||||
|
if nd:
|
||||||
|
if nd.right:
|
||||||
|
nd = nd.right
|
||||||
|
while nd.left:
|
||||||
|
nd = nd.left
|
||||||
|
return nd
|
||||||
|
else:return self.getParent(nd)
|
||||||
|
def setRoot(self,nd):
|
||||||
|
if nd is not None: nd.parent=None
|
||||||
|
self.root= nd
|
||||||
|
def transferParent(self,origin,new):
|
||||||
|
if origin is self.root:
|
||||||
|
self.root = new
|
||||||
|
else:
|
||||||
|
prt = self.getParent(origin)
|
||||||
|
prt.setChild(new, prt.left is origin)
|
||||||
|
def rotate(self,prt,chd,direction):
|
||||||
|
'''rotate prt, and return new prt, namyly the original chd'''
|
||||||
|
prt.setChild(chd.getChild(direction), not direction)
|
||||||
|
chd.setChild(prt,direction)
|
||||||
|
return chd
|
||||||
|
|
||||||
|
def insert(self,nd):
|
||||||
|
if nd.isBlack: nd.isBlack = False
|
||||||
|
|
||||||
|
if self.root is None:
|
||||||
|
self.setRoot(nd)
|
||||||
|
self.root.isBlack = True
|
||||||
|
else:
|
||||||
|
parent = self.root
|
||||||
|
while parent:
|
||||||
|
if parent == nd : return None
|
||||||
|
isLeft = parent > nd
|
||||||
|
chd = parent.getChild(isLeft)
|
||||||
|
if chd is None:
|
||||||
|
parent.setChild(nd,isLeft)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
parent = chd
|
||||||
|
self.fixUpInsert(parent,nd)
|
||||||
|
def fixUpInsert(self,parent,nd):
|
||||||
|
''' adjust color and level, there are two red nodes: the new one and its parent'''
|
||||||
|
while not self.checkBlack(parent):
|
||||||
|
grand = self.getParent(parent)
|
||||||
|
isLeftPrt = grand.left is parent
|
||||||
|
uncle = grand.getChild(not isLeftPrt)
|
||||||
|
if not self.checkBlack(uncle):
|
||||||
|
# case 1: new node's uncle is red
|
||||||
|
self.setBlack(grand, False)
|
||||||
|
self.setBlack(grand.left, True)
|
||||||
|
self.setBlack(grand.right, True)
|
||||||
|
nd = grand
|
||||||
|
parent = self.getParent(nd)
|
||||||
|
else:
|
||||||
|
# case 2: new node's uncle is black(including nil leaf)
|
||||||
|
isLeftNode = parent.left is nd
|
||||||
|
if isLeftNode ^ isLeftPrt:
|
||||||
|
# case 2.1 the new node is inserted in left-right or right-left form
|
||||||
|
# grand grand
|
||||||
|
# parent or parent
|
||||||
|
# nd nd
|
||||||
|
self.rotate(parent,nd,isLeftPrt) #parent rotate
|
||||||
|
grand.setChild(nd,isLeftPrt)
|
||||||
|
nd,parent = parent,nd
|
||||||
|
# case 2.2 the new node is inserted in left-left or right-right form
|
||||||
|
# grand grand
|
||||||
|
# parent or parent
|
||||||
|
# nd nd
|
||||||
|
|
||||||
|
# grand rotate
|
||||||
|
|
||||||
|
self.rotate(grand,parent,not isLeftPrt)
|
||||||
|
self.setBlack(grand, False)
|
||||||
|
self.setBlack(parent, True)
|
||||||
|
self.transferParent(grand,parent)
|
||||||
|
self.setBlack(self.root,True)
|
||||||
|
|
||||||
|
def copyNode(self,src,des):
|
||||||
|
'''when deleting a node which has two kids,
|
||||||
|
copy its succesor's data to his position
|
||||||
|
data exclude left, right , isBlack
|
||||||
|
'''
|
||||||
|
des.val = src.val
|
||||||
|
def delete(self,val):
|
||||||
|
'''delete node in a binary search tree'''
|
||||||
|
if isinstance(val,node): val = val.val
|
||||||
|
nd = self.find(val)
|
||||||
|
if nd is None: return
|
||||||
|
y = None
|
||||||
|
if nd.left and nd.right:
|
||||||
|
y= self.getSuccessor(nd)
|
||||||
|
else:
|
||||||
|
y = nd
|
||||||
|
py = self.getParent(y)
|
||||||
|
x = y.left if y.left else y.right
|
||||||
|
if py is None:
|
||||||
|
self.root = x
|
||||||
|
else:
|
||||||
|
py.setChild(x,py.left is y)
|
||||||
|
if y != nd:
|
||||||
|
self.copyNode(y,nd)
|
||||||
|
|
||||||
|
if self.checkBlack(y): self.fixUpDel(py,x)
|
||||||
|
|
||||||
|
|
||||||
|
def fixUpDel(self,prt,chd):
|
||||||
|
''' adjust colors and rotate '''
|
||||||
|
while self.root != chd and self.checkBlack(chd):
|
||||||
|
isLeft = prt.left is chd
|
||||||
|
brother = prt.getChild(not isLeft)
|
||||||
|
# brother is black
|
||||||
|
lb = self.checkBlack(brother.getChild(isLeft))
|
||||||
|
rb = self.checkBlack(brother.getChild(not isLeft))
|
||||||
|
if not self.checkBlack(brother):
|
||||||
|
# case 1: brother is red. converted to case 2,3,4
|
||||||
|
# prt (isLeft) rotate
|
||||||
|
|
||||||
|
self.rotate(prt,brother,isLeft)
|
||||||
|
|
||||||
|
self.setBlack(prt,False)
|
||||||
|
self.setBlack(brother,True)
|
||||||
|
|
||||||
|
self.transferParent(prt,brother)
|
||||||
|
elif lb and rb:
|
||||||
|
# case 2: brother is black and two kids are black.
|
||||||
|
# conveted to the begin case
|
||||||
|
self.setBlack(brother,False)
|
||||||
|
chd = prt
|
||||||
|
prt = self.getParent(chd)
|
||||||
|
else:
|
||||||
|
if rb:
|
||||||
|
# case 3: brother is black and left kid is red and right child is black
|
||||||
|
# uncle's son is nephew, and niece for uncle's daughter
|
||||||
|
nephew = brother.getChild(isLeft)
|
||||||
|
self.setBlack(nephew,True)
|
||||||
|
self.setBlack(brother,False)
|
||||||
|
|
||||||
|
# brother (not isLeft) rotate
|
||||||
|
prt.setChild(nephew,not isLeft)
|
||||||
|
self.rotate(brother,nephew,not isLeft)
|
||||||
|
brother = nephew
|
||||||
|
|
||||||
|
# case 4: brother is black and right child is red
|
||||||
|
brother.isBlack = prt.isBlack
|
||||||
|
self.setBlack(prt,True)
|
||||||
|
self.setBlack(brother.getChild(not isLeft),True)
|
||||||
|
|
||||||
|
# prt left rotate
|
||||||
|
self.rotate(prt,brother,isLeft)
|
||||||
|
|
||||||
|
self.transferParent(prt,brother)
|
||||||
|
|
||||||
|
chd = self.root
|
||||||
|
self.setBlack(chd,True)
|
||||||
|
|
||||||
|
def sort(self,reverse = False):
|
||||||
|
''' return a generator of sorted data'''
|
||||||
|
def inOrder(root):
|
||||||
|
if root is None:return
|
||||||
|
if reverse:
|
||||||
|
yield from inOrder(root.right)
|
||||||
|
else:
|
||||||
|
yield from inOrder(root.left)
|
||||||
|
yield root
|
||||||
|
if reverse:
|
||||||
|
yield from inOrder(root.left)
|
||||||
|
else:
|
||||||
|
yield from inOrder(root.right)
|
||||||
|
yield from inOrder(self.root)
|
||||||
|
|
||||||
|
def display(self):
|
||||||
|
def getHeight(nd):
|
||||||
|
if nd is None:return 0
|
||||||
|
return max(getHeight(nd.left),getHeight(nd.right)) +1
|
||||||
|
def levelVisit(root):
|
||||||
|
from collections import deque
|
||||||
|
lst = deque([root])
|
||||||
|
level = []
|
||||||
|
h = getHeight(root)
|
||||||
|
ct = lv = 0
|
||||||
|
while 1:
|
||||||
|
ct+=1
|
||||||
|
nd = lst.popleft()
|
||||||
|
if ct >= 2**lv:
|
||||||
|
lv+=1
|
||||||
|
if lv>h:break
|
||||||
|
level.append([])
|
||||||
|
level[-1].append(str(nd))
|
||||||
|
if nd is not None:
|
||||||
|
lst += [nd.left,nd.right]
|
||||||
|
else:
|
||||||
|
lst +=[None,None]
|
||||||
|
return level
|
||||||
|
def addBlank(lines):
|
||||||
|
width = 5
|
||||||
|
sep = ' '*width
|
||||||
|
n = len(lines)
|
||||||
|
for i,oneline in enumerate(lines):
|
||||||
|
k = 2**(n-i) -1
|
||||||
|
new = [sep*((k-1)//2)]
|
||||||
|
for s in oneline:
|
||||||
|
new.append(s.ljust(width))
|
||||||
|
new.append(sep*k)
|
||||||
|
lines[i] = new
|
||||||
|
return lines
|
||||||
|
|
||||||
|
lines = levelVisit(self.root)
|
||||||
|
lines = addBlank(lines)
|
||||||
|
li = [''.join(line) for line in lines]
|
||||||
|
li.insert(0,'red-black-tree'.rjust(48,'-') + '-'*33)
|
||||||
|
li.append('end'.rjust(42,'-')+'-'*39+'\n')
|
||||||
|
return '\n'.join(li)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.display()
|
||||||
|
|
||||||
|
|
||||||
|
def genNum(n =10):
|
||||||
|
nums =[]
|
||||||
|
for i in range(n):
|
||||||
|
while 1:
|
||||||
|
d = randint(0,100)
|
||||||
|
if d not in nums:
|
||||||
|
nums.append(d)
|
||||||
|
break
|
||||||
|
return nums
|
||||||
|
|
||||||
|
def buildTree(n=10,nums=None,visitor=None):
|
||||||
|
if nums is None or nums ==[]: nums = genNum(n)
|
||||||
|
rbtree = redBlackTree()
|
||||||
|
print(f'build a red-black tree using {nums}')
|
||||||
|
for i in nums:
|
||||||
|
rbtree.insert(node(i))
|
||||||
|
if visitor:
|
||||||
|
visitor(rbtree,i)
|
||||||
|
return rbtree,nums
|
||||||
|
def testInsert(nums=None):
|
||||||
|
def visitor(t,val):
|
||||||
|
print('inserting',val)
|
||||||
|
print(t)
|
||||||
|
rbtree,nums = buildTree(visitor = visitor,nums=nums)
|
||||||
|
print('-'*5+ 'in-order visit' + '-'*5)
|
||||||
|
for i,j in enumerate(rbtree.sort()):
|
||||||
|
print(f'{i+1}: {j}')
|
||||||
|
|
||||||
|
def testSuc(nums=None):
|
||||||
|
rbtree,nums = buildTree(nums=nums)
|
||||||
|
print(rbtree)
|
||||||
|
for i in rbtree.sort():
|
||||||
|
print(f'{i}\'s suc is {rbtree.getSuccessor(i)}')
|
||||||
|
|
||||||
|
def testDelete(nums=None):
|
||||||
|
rbtree,nums = buildTree(nums = nums)
|
||||||
|
print(rbtree)
|
||||||
|
for i in nums:
|
||||||
|
print(f'deleting {i}')
|
||||||
|
rbtree.delete(i)
|
||||||
|
print(rbtree)
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
#lst = [41,38,31,12,19,8]
|
||||||
|
#lst.sort()
|
||||||
|
lst = None
|
||||||
|
lst =[45, 30, 64, 36, 95, 38, 76, 34, 50, 1]
|
||||||
|
testSuc()
|
||||||
|
testInsert(lst)
|
||||||
|
testDelete()
|
124
divideAndConquer/min_distance_of_n_points.py
Normal file
124
divideAndConquer/min_distance_of_n_points.py
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
from random import randint
|
||||||
|
from time import time
|
||||||
|
from functools import total_ordering
|
||||||
|
|
||||||
|
@total_ordering
|
||||||
|
class point:
|
||||||
|
def __init__(self,x,y):
|
||||||
|
self.x=x
|
||||||
|
self.y=y
|
||||||
|
def __neg__(self):
|
||||||
|
return pont(-self.x, -self.y)
|
||||||
|
def __len__(self):
|
||||||
|
return self.norm(2)
|
||||||
|
def __lt__(self,p):
|
||||||
|
return self.x<p.x or (self.x==p.x and self.y<p.y)
|
||||||
|
def __eq__(self,p):
|
||||||
|
return self.x==p.x and self.y == p.y
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self.x,self.y))
|
||||||
|
def __repr__(self):
|
||||||
|
return 'point({},{})'.format(self.x,self.y)
|
||||||
|
def __str__(self):
|
||||||
|
return self.__repr__()
|
||||||
|
def norm(self,n=2):
|
||||||
|
if n<=0: return max(abs(self.x),abs(self.y))
|
||||||
|
return (abs(self.x)**n+abs(self.y)**n)**(1/n)
|
||||||
|
def distance(self,p):
|
||||||
|
return ((self.x-p.x)**2+(self.y-p.y)**2)**0.5
|
||||||
|
|
||||||
|
def minDistance_n2(points):
|
||||||
|
n = len(points)
|
||||||
|
if n<=1: return 0
|
||||||
|
p,q=points[:2]
|
||||||
|
minD = points[0].distance(points[1])
|
||||||
|
for i in range(n-1):
|
||||||
|
for j in range(i+1,n):
|
||||||
|
d = points[i].distance(points[j])
|
||||||
|
if d<minD:
|
||||||
|
minD = d
|
||||||
|
p = points[i]
|
||||||
|
q= points[j]
|
||||||
|
return minD, p,q
|
||||||
|
|
||||||
|
def findif(points, f,reverse = False):
|
||||||
|
n = len(points)
|
||||||
|
rg = range(n-1,-1,-1) if reverse else range(n)
|
||||||
|
for i in rg:
|
||||||
|
if not f(points[i]):
|
||||||
|
return points[i+1:] if reverse else points[:i]
|
||||||
|
return points.copy() # note that don't return exactly points, return a copy one
|
||||||
|
|
||||||
|
def floatEql(f1,f2,epsilon=1e-6):
|
||||||
|
return abs(f1-f2)<epsilon
|
||||||
|
|
||||||
|
def minDistance_nlogn(n_points):
|
||||||
|
def _min(pts):
|
||||||
|
n = len(pts)
|
||||||
|
if n==2: return pts[0].distance(pts[1]) , pts[0],pts[1]
|
||||||
|
if n==3:
|
||||||
|
minD = pts[0].distance(pts[1])
|
||||||
|
p,q = pts[0],pts[1]
|
||||||
|
d2 = pts[2].distance(pts[1])
|
||||||
|
if minD>d2:
|
||||||
|
minD = d2
|
||||||
|
p,q = pts[1], pts[2]
|
||||||
|
d2 = pts[0].distance(pts[2])
|
||||||
|
if minD>d2: return d2, pts[0],pts[2]
|
||||||
|
else : return minD, p,q
|
||||||
|
n2 = n//2
|
||||||
|
mid = (pts[n2].x +pts[n2-1].x)/2
|
||||||
|
s1 = pts[:n2]
|
||||||
|
s2 = pts[n2:]
|
||||||
|
minD ,p,q = _min(s1)
|
||||||
|
d2, p2, q2 = _min(s2)
|
||||||
|
#print('\n\n',minD,p,q,s1)
|
||||||
|
#print(d2,p2,q2,s2)
|
||||||
|
if minD> d2:
|
||||||
|
minD,p,q = d2, p2, q2
|
||||||
|
|
||||||
|
linePoints = findif(s1,lambda pt:floatEql(pt.x,mid),reverse=True)
|
||||||
|
linePoints += findif(s2,lambda pt:floatEql(pt.x,mid))
|
||||||
|
n = len(linePoints)
|
||||||
|
if n>1:
|
||||||
|
for i in range(1,n):
|
||||||
|
dis = linePoints[i].y -linePoints[i-1].y
|
||||||
|
if dis<minD:
|
||||||
|
minD = dis
|
||||||
|
p,q = linePoints[i-1], linePoints[i]
|
||||||
|
leftPoints = findif(s1,lambda pt:pt.x>= mid-minD,reverse=True)
|
||||||
|
rightPoints = findif(s2,lambda pt:pt.x<= mid+minD)
|
||||||
|
for lp in leftPoints:
|
||||||
|
y1,y2 = lp.y-minD, lp.y+minD
|
||||||
|
for rp in rightPoints:
|
||||||
|
if y1< rp.y <y2:
|
||||||
|
dis = lp.distance(rp)
|
||||||
|
if dis< minD:
|
||||||
|
minD = dis
|
||||||
|
p,q = lp,rp
|
||||||
|
return minD, p,q
|
||||||
|
return _min(sorted(n_points))
|
||||||
|
|
||||||
|
def test(f=minDistance_n2):
|
||||||
|
print('\ntest : ', f.__name__)
|
||||||
|
begin = time()
|
||||||
|
minD, p, q = f(points)
|
||||||
|
print('time : {:.6f} s'.format(time()-begin))
|
||||||
|
print('result: {:.2f} {} {}\n'.format(minD, p,q))
|
||||||
|
|
||||||
|
def genData(n,unique=True):
|
||||||
|
if unique:
|
||||||
|
points = set()
|
||||||
|
for i in range(n):
|
||||||
|
points.add(point(randint(1,1000),randint(1,1000)))
|
||||||
|
return list(points)
|
||||||
|
else:return [point(randint(1,1000),randint(1,1000)) for i in range(n)]
|
||||||
|
|
||||||
|
if __name__ =='__main__':
|
||||||
|
n = 10000
|
||||||
|
points = genData(n, unique=True)
|
||||||
|
print('min distance of {} points'.format(n))
|
||||||
|
#print(sorted(points))
|
||||||
|
test(minDistance_n2)
|
||||||
|
test(minDistance_nlogn)
|
||||||
|
|
|
@ -37,7 +37,7 @@ description:
|
||||||
|
|
||||||
<a id="markdown-1-关键字" name="1-关键字"></a>
|
<a id="markdown-1-关键字" name="1-关键字"></a>
|
||||||
# 1. 关键字
|
# 1. 关键字
|
||||||
由于关键字是用来索引数据的, 所以要求它不能变动(如果变动,实际上就是一个新的关键字插入了), 在python 中表现为 imutable. 常为字符串.
|
由于关键字是用来索引数据的, 所以要求它不能变动(如果变动,实际上就是一个新的关键字插入了), 在python 中表现为 immutable. 常为字符串.
|
||||||
|
|
||||||
<a id="markdown-2-映射" name="2-映射"></a>
|
<a id="markdown-2-映射" name="2-映射"></a>
|
||||||
# 2. 映射
|
# 2. 映射
|
||||||
|
|
|
@ -7,7 +7,6 @@ keywords:
|
||||||
mathjax: true
|
mathjax: true
|
||||||
description:
|
description:
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- TOC -->
|
<!-- TOC -->
|
||||||
|
|
||||||
- [1. 定义与性质](#1-定义与性质)
|
- [1. 定义与性质](#1-定义与性质)
|
||||||
|
@ -47,7 +46,6 @@ description:
|
||||||
* right:pointer to right child
|
* right:pointer to right child
|
||||||
* p: pointer to nil leaf
|
* p: pointer to nil leaf
|
||||||
|
|
||||||
|
|
||||||
<a id="markdown-12-红黑性质" name="12-红黑性质"></a>
|
<a id="markdown-12-红黑性质" name="12-红黑性质"></a>
|
||||||
## 1.2. 红黑性质
|
## 1.2. 红黑性质
|
||||||
满足下面的 `红黑性质` 的二叉查找树就是红黑树:
|
满足下面的 `红黑性质` 的二叉查找树就是红黑树:
|
||||||
|
@ -57,7 +55,6 @@ description:
|
||||||
* 红结点的孩子是黑
|
* 红结点的孩子是黑
|
||||||
* 从每个结点出发,通过子孙到达叶子结点的各条路径上 黑结点数相等
|
* 从每个结点出发,通过子孙到达叶子结点的各条路径上 黑结点数相等
|
||||||
|
|
||||||
|
|
||||||
如,叶子结点 是 nil, 即不存储任何东西, 为了编程方便,相对的,存有数据的结点称为内结点
|
如,叶子结点 是 nil, 即不存储任何东西, 为了编程方便,相对的,存有数据的结点称为内结点
|
||||||
![](https://upload-images.jianshu.io/upload_images/7130568-95927d3ca6cc524d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
![](https://upload-images.jianshu.io/upload_images/7130568-95927d3ca6cc524d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
||||||
|
|
||||||
|
@ -99,7 +96,6 @@ $$n \geqslant 2^{h_b(x)} -1 \geqslant 2^{\frac{h}{2}} -1$$
|
||||||
* 然后将新结点的 左右孩子设为 nil , 颜色设为红色
|
* 然后将新结点的 左右孩子设为 nil , 颜色设为红色
|
||||||
* 最后再进行颜色调整以及旋转(维持红黑性质)
|
* 最后再进行颜色调整以及旋转(维持红黑性质)
|
||||||
|
|
||||||
|
|
||||||
这是算法导论[^1]上的算法
|
这是算法导论[^1]上的算法
|
||||||
```python
|
```python
|
||||||
RB-INSERT(T, z)
|
RB-INSERT(T, z)
|
||||||
|
@ -198,7 +194,11 @@ RB-INSERT(T, z)
|
||||||
### 3.2.3. 总体解决方案
|
### 3.2.3. 总体解决方案
|
||||||
我最开始也没有弄清楚, 有点绕晕的感觉, 后来仔细读了书上伪代码, 然后才发现就是一个状态机, 画出来就一目了然了.
|
我最开始也没有弄清楚, 有点绕晕的感觉, 后来仔细读了书上伪代码, 然后才发现就是一个状态机, 画出来就一目了然了.
|
||||||
|
|
||||||
![](https://upload-images.jianshu.io/upload_images/7130568-bd3a0ffca482eb73.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
![](https://upload-images.jianshu.io/upload_images/7130568-53dd71e22a315242.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
现在算是知其然了, 那么怎样知其所以然呢? 即 为什么要分类这三个 case, 不重不漏了吗?
|
现在算是知其然了, 那么怎样知其所以然呢? 即 为什么要分类这三个 case, 不重不漏了吗?
|
||||||
|
@ -287,12 +287,10 @@ color[root[T]] ← BLACK
|
||||||
|
|
||||||
* 当 z 孩子全是 nil (y==z): 直接让其双亲对应的孩子为 nil
|
* 当 z 孩子全是 nil (y==z): 直接让其双亲对应的孩子为 nil
|
||||||
* 当 z 只有一个非 nil 孩子 x (y==z):
|
* 当 z 只有一个非 nil 孩子 x (y==z):
|
||||||
|
|
||||||
1. 如果 z 为根, 则让 x 为根.
|
1. 如果 z 为根, 则让 x 为根.
|
||||||
2. 让 y 的双亲连接到 x
|
2. 让 y 的双亲连接到 x
|
||||||
* 当 z 有两个非nil孩子(y!=z): 复制其后继 y 的内容到 z (除了指针,颜色) , 将其后继 y 的孩子(最多只有一个 非 nil ,不然就不是后继了)连接到其后继的双亲, 删除 其后继y,
|
* 当 z 有两个非nil孩子(y!=z): 复制其后继 y 的内容到 z (除了指针,颜色) , 将其后继 y 的孩子(最多只有一个 非 nil ,不然就不是后继了)连接到其后继的双亲, 删除 其后继y,
|
||||||
|
|
||||||
|
|
||||||
即[^3] 如果要删除有两个孩子的结点 z , 则找到它的后继y(前趋同理), 可以推断 y 一定没有左孩子, 右孩子可能有,可能没有. 也就是最多一个孩子.
|
即[^3] 如果要删除有两个孩子的结点 z , 则找到它的后继y(前趋同理), 可以推断 y 一定没有左孩子, 右孩子可能有,可能没有. 也就是最多一个孩子.
|
||||||
所以将 y 的值复制到 x 位置, 现在相当于删除 y 处的结点.
|
所以将 y 的值复制到 x 位置, 现在相当于删除 y 处的结点.
|
||||||
这样就化为 删除的结点最多一个孩子的情况.
|
这样就化为 删除的结点最多一个孩子的情况.
|
||||||
|
@ -321,7 +319,6 @@ color[root[T]] ← BLACK
|
||||||
* x 指向根,这时可以简单地消除额外的黑色
|
* x 指向根,这时可以简单地消除额外的黑色
|
||||||
* 颜色修改与旋转
|
* 颜色修改与旋转
|
||||||
|
|
||||||
|
|
||||||
在 while 中, x 总是指向具有双重黑色的那个非根结点, 在第 2 行中要判断 x 是其双亲的左右孩子
|
在 while 中, x 总是指向具有双重黑色的那个非根结点, 在第 2 行中要判断 x 是其双亲的左右孩子
|
||||||
w 表示 x 的相抵. w 不能为 nil(因为 x 是双重黑色)
|
w 表示 x 的相抵. w 不能为 nil(因为 x 是双重黑色)
|
||||||
|
|
||||||
|
@ -330,20 +327,19 @@ w 表示 x 的相抵. w 不能为 nil(因为 x 是双重黑色)
|
||||||
|
|
||||||
即
|
即
|
||||||
* x 的兄弟 w 是红色的
|
* x 的兄弟 w 是红色的
|
||||||
|
|
||||||
![](https://upload-images.jianshu.io/upload_images/7130568-cd139202bdc5406f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
![](https://upload-images.jianshu.io/upload_images/7130568-cd139202bdc5406f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
||||||
* x 的兄弟 w 是黑色的, w的两个孩子都是黑色的
|
* x 的兄弟 w 是黑色的, w的两个孩子都是黑色的
|
||||||
|
|
||||||
|
|
||||||
* x 的兄弟 w 是黑色的, w 的左孩子是红,右孩子是黑
|
* x 的兄弟 w 是黑色的, w 的左孩子是红,右孩子是黑
|
||||||
* x 的兄弟 w 是黑色的, w 的孩子是红色的
|
* x 的兄弟 w 是黑色的, w 的孩子是红色的
|
||||||
|
|
||||||
|
|
||||||
>>注意上面都是先考虑的左边, 右边可以对称地处理.
|
>>注意上面都是先考虑的左边, 右边可以对称地处理.
|
||||||
|
|
||||||
同插入一样, 为了便于理解, 可以作出状态机.
|
同插入一样, 为了便于理解, 可以作出状态机.
|
||||||
而且这些情形都是归纳化简了的, 你也可以枚举列出基本的全部情形.
|
而且这些情形都是归纳化简了的, 你也可以枚举列出基本的全部情形.
|
||||||
![](https://upload-images.jianshu.io/upload_images/7130568-d6e8a332afade8d5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
|
||||||
|
![](https://upload-images.jianshu.io/upload_images/7130568-005e2a7d55860559.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
||||||
|
|
||||||
|
|
||||||
<a id="markdown-5-数据结构的扩张" name="5-数据结构的扩张"></a>
|
<a id="markdown-5-数据结构的扩张" name="5-数据结构的扩张"></a>
|
||||||
# 5. 数据结构的扩张
|
# 5. 数据结构的扩张
|
||||||
|
@ -374,27 +370,22 @@ def find(root,i):
|
||||||
<a id="markdown-6-python-代码" name="6-python-代码"></a>
|
<a id="markdown-6-python-代码" name="6-python-代码"></a>
|
||||||
# 6. python 代码
|
# 6. python 代码
|
||||||
|
|
||||||
**[github地址](https://github.com/mbinary/algorithm-and-data-structure.git)**
|
**[github地址](https://github.com/mbinary/algorithm-in-python.git)**
|
||||||
|
|
||||||
我的代码有两点不同
|
我用了 setChild, getChild 来简化代码量, 其他的基本上是按照算法导论上的伪代码提到的case 来实现的. 然后display 只是测试的时候,为了方便调试而层序遍历打印出来
|
||||||
* 用了 setChild, getChild 来简化代码量
|
|
||||||
* 每个结点没有上面的 p 域, 即指向 nil leaf的,我直接让 left, right 为 `None`, 然后定义了两个函数 `setBlack`, `checkBlack` 来操作 颜色数据 isBlack(当为 True 时代表黑色,否则为红). 如果为 None, 这两个函数也能正确的处理.可以直接见代码
|
|
||||||
|
|
||||||
|
|
||||||
其他的基本上是按照算法导论上的伪代码提到的case 来实现的. 然后display 只是测试的时候,为了方便调试而层序遍历打印出来
|
|
||||||
|
|
||||||
效果如下
|
效果如下
|
||||||
![](https://upload-images.jianshu.io/upload_images/7130568-721e18cc44dec604.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
![](https://upload-images.jianshu.io/upload_images/7130568-721e18cc44dec604.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
||||||
|
|
||||||
```python
|
```python
|
||||||
'''
|
''' mbinary
|
||||||
#########################################################################
|
#########################################################################
|
||||||
# File : redBlackTree.py
|
# File : redBlackTree.py
|
||||||
# Author: mbinary
|
# Author: mbinary
|
||||||
# Mail: zhuheqin1@gmail.com
|
# Mail: zhuheqin1@gmail.com
|
||||||
# Blog: https://mbinary.coding.me
|
# Blog: https://mbinary.coding.me
|
||||||
# Github: https://github.com/mbinary
|
# Github: https://github.com/mbinary
|
||||||
# Created Time: 2018-07-12 20:34
|
# Created Time: 2018-07-14 16:15
|
||||||
# Description:
|
# Description:
|
||||||
#########################################################################
|
#########################################################################
|
||||||
'''
|
'''
|
||||||
|
@ -407,14 +398,17 @@ class node:
|
||||||
self.val =val
|
self.val =val
|
||||||
self.left = left
|
self.left = left
|
||||||
self.right = right
|
self.right = right
|
||||||
|
self.parent= None
|
||||||
self.isBlack = isBlack
|
self.isBlack = isBlack
|
||||||
def __lt__(self,nd):
|
def __lt__(self,nd):
|
||||||
return self.val < nd.val
|
return self.val < nd.val
|
||||||
def __eq__(self,nd):
|
def __eq__(self,nd):
|
||||||
return nd is not None and self.val == nd.val
|
return nd is not None and self.val == nd.val
|
||||||
def setChild(self,nd,isLeft = True):
|
def setChild(self,nd,isLeft):
|
||||||
if isLeft: self.left = nd
|
if isLeft: self.left = nd
|
||||||
else: self.right = nd
|
else: self.right = nd
|
||||||
|
if nd is not None: nd.parent = self
|
||||||
|
|
||||||
def getChild(self,isLeft):
|
def getChild(self,isLeft):
|
||||||
if isLeft: return self.left
|
if isLeft: return self.left
|
||||||
else: return self.right
|
else: return self.right
|
||||||
|
@ -422,7 +416,8 @@ class node:
|
||||||
return self.val is not None
|
return self.val is not None
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
color = 'B' if self.isBlack else 'R'
|
color = 'B' if self.isBlack else 'R'
|
||||||
return f'{color}-{self.val:}'
|
val = '-' if self.parent==None else self.parent.val
|
||||||
|
return f'{color}-{self.val}'
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f'node({self.val},isBlack={self.isBlack})'
|
return f'node({self.val},isBlack={self.isBlack})'
|
||||||
class redBlackTree:
|
class redBlackTree:
|
||||||
|
@ -440,6 +435,159 @@ class redBlackTree:
|
||||||
if isBlack is None or isBlack:
|
if isBlack is None or isBlack:
|
||||||
nd.isBlack = True
|
nd.isBlack = True
|
||||||
else:nd.isBlack = False
|
else:nd.isBlack = False
|
||||||
|
def setRoot(self,nd):
|
||||||
|
if nd is not None: nd.parent=None
|
||||||
|
self.root= nd
|
||||||
|
def find(self,val):
|
||||||
|
nd = self.root
|
||||||
|
while nd:
|
||||||
|
if nd.val ==val:
|
||||||
|
return nd
|
||||||
|
else:
|
||||||
|
nd = nd.getChild(nd.val>val)
|
||||||
|
def getSuccessor(self,nd):
|
||||||
|
if nd:
|
||||||
|
if nd.right:
|
||||||
|
nd = nd.right
|
||||||
|
while nd.left:
|
||||||
|
nd = nd.left
|
||||||
|
return nd
|
||||||
|
else:
|
||||||
|
while nd.parent is not None and nd.parent.right is nd:
|
||||||
|
nd = nd.parent
|
||||||
|
return None if nd is self.root else nd.parent
|
||||||
|
def rotate(self,prt,chd):
|
||||||
|
'''rotate prt with the center of chd'''
|
||||||
|
if self.root is prt:
|
||||||
|
self.setRoot(chd)
|
||||||
|
else:
|
||||||
|
prt.parent.setChild(chd, prt.parent.left is prt)
|
||||||
|
isLeftChd = prt.left is chd
|
||||||
|
prt.setChild(chd.getChild(not isLeftChd), isLeftChd)
|
||||||
|
chd.setChild(prt,not isLeftChd)
|
||||||
|
|
||||||
|
def insert(self,nd):
|
||||||
|
if nd.isBlack: nd.isBlack = False
|
||||||
|
|
||||||
|
if self.root is None:
|
||||||
|
self.setRoot(nd)
|
||||||
|
self.root.isBlack = True
|
||||||
|
else:
|
||||||
|
parent = self.root
|
||||||
|
while parent:
|
||||||
|
if parent == nd : return None
|
||||||
|
isLeft = parent > nd
|
||||||
|
chd = parent.getChild(isLeft)
|
||||||
|
if chd is None:
|
||||||
|
parent.setChild(nd,isLeft)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
parent = chd
|
||||||
|
self.fixUpInsert(parent,nd)
|
||||||
|
def fixUpInsert(self,parent,nd):
|
||||||
|
''' adjust color and level, there are two red nodes: the new one and its parent'''
|
||||||
|
while not self.checkBlack(parent):
|
||||||
|
grand = parent.parent
|
||||||
|
isLeftPrt = grand.left is parent
|
||||||
|
uncle = grand.getChild(not isLeftPrt)
|
||||||
|
if not self.checkBlack(uncle):
|
||||||
|
# case 1: new node's uncle is red
|
||||||
|
self.setBlack(grand, False)
|
||||||
|
self.setBlack(grand.left, True)
|
||||||
|
self.setBlack(grand.right, True)
|
||||||
|
nd = grand
|
||||||
|
parent = nd.parent
|
||||||
|
else:
|
||||||
|
# case 2: new node's uncle is black(including nil leaf)
|
||||||
|
isLeftNode = parent.left is nd
|
||||||
|
if isLeftNode ^ isLeftPrt:
|
||||||
|
# case 2.1 the new node is inserted in left-right or right-left form
|
||||||
|
# grand grand
|
||||||
|
# parent or parent
|
||||||
|
# nd nd
|
||||||
|
self.rotate(parent,nd) #parent rotate
|
||||||
|
nd,parent = parent,nd
|
||||||
|
# case 3 (case 2.2) the new node is inserted in left-left or right-right form
|
||||||
|
# grand grand
|
||||||
|
# parent or parent
|
||||||
|
# nd nd
|
||||||
|
|
||||||
|
self.setBlack(grand, False)
|
||||||
|
self.setBlack(parent, True)
|
||||||
|
self.rotate(grand,parent)
|
||||||
|
self.setBlack(self.root,True)
|
||||||
|
|
||||||
|
def copyNode(self,src,des):
|
||||||
|
'''when deleting a node which has two kids,
|
||||||
|
copy its succesor's data to his position
|
||||||
|
data exclude left, right , isBlack
|
||||||
|
'''
|
||||||
|
des.val = src.val
|
||||||
|
def delete(self,val):
|
||||||
|
'''delete node in a binary search tree'''
|
||||||
|
if isinstance(val,node): val = val.val
|
||||||
|
nd = self.find(val)
|
||||||
|
if nd is None: return
|
||||||
|
self._delete(nd)
|
||||||
|
def _delete(self,nd):
|
||||||
|
y = None
|
||||||
|
if nd.left and nd.right:
|
||||||
|
y= self.getSuccessor(nd)
|
||||||
|
else:
|
||||||
|
y = nd
|
||||||
|
py = y.parent
|
||||||
|
x = y.left if y.left else y.right
|
||||||
|
if py is None:
|
||||||
|
self.setRoot(x)
|
||||||
|
else:
|
||||||
|
py.setChild(x,py.left is y)
|
||||||
|
if y != nd:
|
||||||
|
self.copyNode(y,nd)
|
||||||
|
if self.checkBlack(y): self.fixUpDel(py,x)
|
||||||
|
|
||||||
|
def fixUpDel(self,prt,chd):
|
||||||
|
''' adjust colors and rotate '''
|
||||||
|
while self.root != chd and self.checkBlack(chd):
|
||||||
|
isLeft =prt.left is chd
|
||||||
|
brother = prt.getChild(not isLeft)
|
||||||
|
# brother is black
|
||||||
|
lb = self.checkBlack(brother.getChild(isLeft))
|
||||||
|
rb = self.checkBlack(brother.getChild(not isLeft))
|
||||||
|
if not self.checkBlack(brother):
|
||||||
|
# case 1: brother is red. converted to case 2,3,4
|
||||||
|
|
||||||
|
self.setBlack(prt,False)
|
||||||
|
self.setBlack(brother,True)
|
||||||
|
self.rotate(prt,brother)
|
||||||
|
|
||||||
|
elif lb and rb:
|
||||||
|
# case 2: brother is black and two kids are black.
|
||||||
|
# conveted to the begin case
|
||||||
|
self.setBlack(brother,False)
|
||||||
|
chd = prt
|
||||||
|
prt= chd.parent
|
||||||
|
else:
|
||||||
|
if rb:
|
||||||
|
# case 3: brother is black and left kid is red and right child is black
|
||||||
|
# rotate bro to make g w wl wr in one line
|
||||||
|
# uncle's son is nephew, and niece for uncle's daughter
|
||||||
|
nephew = brother.getChild(isLeft)
|
||||||
|
self.setBlack(nephew,True)
|
||||||
|
self.setBlack(brother,False)
|
||||||
|
|
||||||
|
# brother (not isLeft) rotate
|
||||||
|
self.rotate(brother,nephew)
|
||||||
|
brother = nephew
|
||||||
|
|
||||||
|
# case 4: brother is black and right child is red
|
||||||
|
brother.isBlack = prt.isBlack
|
||||||
|
self.setBlack(prt,True)
|
||||||
|
self.setBlack(brother.getChild(not isLeft),True)
|
||||||
|
|
||||||
|
self.rotate(prt,brother)
|
||||||
|
chd = self.root
|
||||||
|
self.setBlack(chd,True)
|
||||||
|
|
||||||
def sort(self,reverse = False):
|
def sort(self,reverse = False):
|
||||||
''' return a generator of sorted data'''
|
''' return a generator of sorted data'''
|
||||||
def inOrder(root):
|
def inOrder(root):
|
||||||
|
@ -454,184 +602,6 @@ class redBlackTree:
|
||||||
else:
|
else:
|
||||||
yield from inOrder(root.right)
|
yield from inOrder(root.right)
|
||||||
yield from inOrder(self.root)
|
yield from inOrder(self.root)
|
||||||
def getParent(self,chd):
|
|
||||||
'''note that use is to find real node when different nodes have euqiv val'''
|
|
||||||
if self.root is chd:return None
|
|
||||||
nd = self.root
|
|
||||||
while nd:
|
|
||||||
if nd>chd and nd.left is not None:
|
|
||||||
if nd.left is chd: return nd
|
|
||||||
else: nd = nd.left
|
|
||||||
elif nd<chd and nd.right is not None:
|
|
||||||
if nd.right is chd: return nd
|
|
||||||
else: nd = nd.right
|
|
||||||
def find(self,val):
|
|
||||||
nd = self.root
|
|
||||||
while nd:
|
|
||||||
if nd.val ==val:
|
|
||||||
return nd
|
|
||||||
elif nd.val>val:
|
|
||||||
nd = nd.left
|
|
||||||
else:
|
|
||||||
nd = nd.right
|
|
||||||
def getSuccessor(self,nd):
|
|
||||||
if nd:
|
|
||||||
if nd.right:
|
|
||||||
nd = nd.right
|
|
||||||
while nd.left:
|
|
||||||
nd = nd.left
|
|
||||||
return nd
|
|
||||||
else:return self.getParent(nd)
|
|
||||||
def transferParent(self,origin,new):
|
|
||||||
if origin is self.root:
|
|
||||||
self.root = new
|
|
||||||
else:
|
|
||||||
prt = self.getParent(origin)
|
|
||||||
prt.setChild(new, prt.left is origin)
|
|
||||||
|
|
||||||
def insert(self,nd):
|
|
||||||
if not isinstance(nd,node):
|
|
||||||
nd = node(nd)
|
|
||||||
elif nd.isBlack: nd.isBlack = False
|
|
||||||
|
|
||||||
if self.root is None:
|
|
||||||
self.root = nd
|
|
||||||
self.root.isBlack = True
|
|
||||||
else:
|
|
||||||
parent = self.root
|
|
||||||
while parent:
|
|
||||||
if parent == nd : return None
|
|
||||||
if parent>nd:
|
|
||||||
if parent.left :
|
|
||||||
parent = parent.left
|
|
||||||
else:
|
|
||||||
parent.left = nd
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if parent.right:
|
|
||||||
parent = parent.right
|
|
||||||
else:
|
|
||||||
parent.right = nd
|
|
||||||
break
|
|
||||||
self.fixUpInsert(parent,nd)
|
|
||||||
def fixUpInsert(self,parent,nd):
|
|
||||||
''' adjust color and level, there are two red nodes: the new one and its parent'''
|
|
||||||
while not self.checkBlack(parent):
|
|
||||||
grand = self.getParent(parent)
|
|
||||||
isLeftPrt = grand.left is parent
|
|
||||||
uncle = grand.getChild(not isLeftPrt)
|
|
||||||
if not self.checkBlack(uncle):
|
|
||||||
# case 1: new node's uncle is red
|
|
||||||
self.setBlack(grand, False)
|
|
||||||
self.setBlack(grand.left, True)
|
|
||||||
self.setBlack(grand.right, True)
|
|
||||||
nd = grand
|
|
||||||
parent = self.getParent(nd)
|
|
||||||
else:
|
|
||||||
# case 2: new node's uncle is black(including nil leaf)
|
|
||||||
isLeftNode = parent.left is nd
|
|
||||||
if isLeftNode ^ isLeftPrt:
|
|
||||||
# case 2.1 the new node is inserted in left-right or right-left form
|
|
||||||
# grand grand
|
|
||||||
# parent or parent
|
|
||||||
# nd nd
|
|
||||||
parent.setChild(nd.getChild(isLeftPrt),not isLeftPrt)
|
|
||||||
nd.setChild(parent,isLeftPrt)
|
|
||||||
grand.setChild(nd,isLeftPrt)
|
|
||||||
nd,parent = parent,nd
|
|
||||||
# case 2.2 the new node is inserted in left-left or right-right form
|
|
||||||
# grand grand
|
|
||||||
# parent or parent
|
|
||||||
# nd nd
|
|
||||||
grand.setChild(parent.getChild(not isLeftPrt),isLeftPrt)
|
|
||||||
parent.setChild(grand,not isLeftPrt)
|
|
||||||
self.setBlack(grand, False)
|
|
||||||
self.setBlack(parent, True)
|
|
||||||
self.transferParent(grand,parent)
|
|
||||||
self.setBlack(self.root,True)
|
|
||||||
|
|
||||||
def copyNode(self,src,des):
|
|
||||||
'''when deleting a node which has two kids,
|
|
||||||
copy its succesor's data to his position
|
|
||||||
data exclude left, right , isBlack
|
|
||||||
'''
|
|
||||||
des.val = src.val
|
|
||||||
def delete(self,nd):
|
|
||||||
'''delete node in a binary search tree'''
|
|
||||||
if not isinstance(nd,node):
|
|
||||||
nd = self.find(nd)
|
|
||||||
if nd is None: return
|
|
||||||
y = None
|
|
||||||
if nd.left and nd.right:
|
|
||||||
y= self.getSuccessor(nd)
|
|
||||||
else:
|
|
||||||
y = nd
|
|
||||||
py = self.getParent(y)
|
|
||||||
x = y.left if y.left else y.right
|
|
||||||
if py is None:
|
|
||||||
self.root = x
|
|
||||||
elif y is py.left:
|
|
||||||
py.left = x
|
|
||||||
else:
|
|
||||||
py.right = x
|
|
||||||
if y != nd:
|
|
||||||
self.copyNode(y,nd)
|
|
||||||
|
|
||||||
if self.checkBlack(y): self.fixUpDel(py,x)
|
|
||||||
|
|
||||||
|
|
||||||
def fixUpDel(self,prt,chd):
|
|
||||||
''' adjust colors and rotate '''
|
|
||||||
while self.root != chd and self.checkBlack(chd):
|
|
||||||
isLeft = prt.left is chd
|
|
||||||
brother = prt.getChild(not isLeft)
|
|
||||||
# brother is black
|
|
||||||
lb = self.checkBlack(brother.getChild(isLeft))
|
|
||||||
rb = self.checkBlack(brother.getChild(not isLeft))
|
|
||||||
if not self.checkBlack(brother):
|
|
||||||
# case 1: brother is red. converted to case 2,3,4
|
|
||||||
# prt (isLeft) rotate
|
|
||||||
prt.setChild(brother.getChild(isLeft), not isLeft)
|
|
||||||
brother.setChild(prt, isLeft)
|
|
||||||
|
|
||||||
self.setBlack(prt,False)
|
|
||||||
self.setBlack(brother,True)
|
|
||||||
|
|
||||||
self.transferParent(prt,brother)
|
|
||||||
elif lb and rb:
|
|
||||||
# case 2: brother is black and two kids are black.
|
|
||||||
# conveted to the begin case
|
|
||||||
self.setBlack(brother,False)
|
|
||||||
chd = prt
|
|
||||||
prt = self.getParent(chd)
|
|
||||||
else:
|
|
||||||
if rb:
|
|
||||||
# case 3: brother is black and left kid is red and right child is black
|
|
||||||
# uncle's son is nephew, and niece for uncle's daughter
|
|
||||||
nephew = brother.getChild(isLeft)
|
|
||||||
self.setBlack(nephew,True)
|
|
||||||
self.setBlack(brother,False)
|
|
||||||
|
|
||||||
# brother (not isLeft) rotate
|
|
||||||
prt.setChild(nephew,not isLeft)
|
|
||||||
brother.setChild(nephew.getChild(not isLeft),isLeft)
|
|
||||||
nephew.setChild(brother, not isLeft)
|
|
||||||
brother = nephew
|
|
||||||
|
|
||||||
# case 4: brother is black and right child is red
|
|
||||||
brother.isBlack = prt.isBlack
|
|
||||||
self.setBlack(prt,True)
|
|
||||||
self.setBlack(brother.getChild(not isLeft),True)
|
|
||||||
|
|
||||||
# prt left rotate
|
|
||||||
prt.setChild(brother.getChild(isLeft),not isLeft)
|
|
||||||
brother.setChild(prt,isLeft)
|
|
||||||
|
|
||||||
self.transferParent(prt,brother)
|
|
||||||
|
|
||||||
chd = self.root
|
|
||||||
self.setBlack(chd,True)
|
|
||||||
|
|
||||||
|
|
||||||
def display(self):
|
def display(self):
|
||||||
def getHeight(nd):
|
def getHeight(nd):
|
||||||
|
@ -657,7 +627,7 @@ class redBlackTree:
|
||||||
lst +=[None,None]
|
lst +=[None,None]
|
||||||
return level
|
return level
|
||||||
def addBlank(lines):
|
def addBlank(lines):
|
||||||
width = 5
|
width = 1+len(str(self.root))
|
||||||
sep = ' '*width
|
sep = ' '*width
|
||||||
n = len(lines)
|
n = len(lines)
|
||||||
for i,oneline in enumerate(lines):
|
for i,oneline in enumerate(lines):
|
||||||
|
@ -672,15 +642,18 @@ class redBlackTree:
|
||||||
lines = levelVisit(self.root)
|
lines = levelVisit(self.root)
|
||||||
lines = addBlank(lines)
|
lines = addBlank(lines)
|
||||||
li = [''.join(line) for line in lines]
|
li = [''.join(line) for line in lines]
|
||||||
li.insert(0,'red-black-tree'.rjust(48,'-') + '-'*33)
|
length = 10 if li==[] else max(len(i) for i in li)//2
|
||||||
li.append('end'.rjust(42,'-')+'-'*39+'\n')
|
begin ='\n'+ 'red-black-tree'.rjust(length+14,'-') + '-'*(length)
|
||||||
return '\n'.join(li)
|
end = '-'*(length*2+14)+'\n'
|
||||||
|
return '\n'.join([begin,*li,end])
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.display()
|
return self.display()
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
测试代码
|
测试代码
|
||||||
```python
|
```python
|
||||||
|
|
||||||
def genNum(n =10):
|
def genNum(n =10):
|
||||||
nums =[]
|
nums =[]
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
|
@ -696,36 +669,37 @@ def buildTree(n=10,nums=None,visitor=None):
|
||||||
rbtree = redBlackTree()
|
rbtree = redBlackTree()
|
||||||
print(f'build a red-black tree using {nums}')
|
print(f'build a red-black tree using {nums}')
|
||||||
for i in nums:
|
for i in nums:
|
||||||
rbtree.insert(i)
|
rbtree.insert(node(i))
|
||||||
if visitor:
|
if visitor:
|
||||||
visitor(rbtree)
|
visitor(rbtree,i)
|
||||||
return rbtree,nums
|
return rbtree,nums
|
||||||
def testInsert():
|
def testInsert(nums=None):
|
||||||
def visitor(t):
|
def visitor(t,val):
|
||||||
|
print('inserting', val)
|
||||||
print(t)
|
print(t)
|
||||||
rbtree,nums = buildTree(visitor = visitor)
|
rbtree,nums = buildTree(visitor = visitor,nums=nums)
|
||||||
print('-'*5+ 'in-order visit' + '-'*5)
|
print('-'*5+ 'in-order visit' + '-'*5)
|
||||||
for i,j in enumerate(rbtree.sort()):
|
for i,j in enumerate(rbtree.sort()):
|
||||||
print(f'{i+1}: {j}')
|
print(f'{i+1}: {j}')
|
||||||
|
|
||||||
def testSuc():
|
def testSuc(nums=None):
|
||||||
rbtree,nums = buildTree()
|
rbtree,nums = buildTree(nums=nums)
|
||||||
for i in rbtree.sort():
|
for i in rbtree.sort():
|
||||||
print(f'{i}\'s suc is {rbtree.getSuccessor(i)}')
|
print(f'{i}\'s suc is {rbtree.getSuccessor(i)}')
|
||||||
|
|
||||||
def testDelete():
|
def testDelete(nums=None):
|
||||||
#nums = [2,3,3,2,6,7,2,1]
|
|
||||||
nums = None
|
|
||||||
rbtree,nums = buildTree(nums = nums)
|
rbtree,nums = buildTree(nums = nums)
|
||||||
print(rbtree)
|
print(rbtree)
|
||||||
for i in nums:
|
for i in sorted(nums):
|
||||||
print(f'deleting {i}')
|
print(f'deleting {i}')
|
||||||
rbtree.delete(i)
|
rbtree.delete(i)
|
||||||
print(rbtree)
|
print(rbtree)
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__=='__main__':
|
||||||
#testSuc()
|
lst =[45, 30, 64, 36, 95, 38, 76, 34, 50, 1]
|
||||||
#testInsert()
|
lst = [0,3,5,6,26,25,8,19,15,16,17]
|
||||||
|
#testSuc(lst)
|
||||||
|
#testInsert(lst)
|
||||||
testDelete()
|
testDelete()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -735,3 +709,4 @@ if __name__=='__main__':
|
||||||
|
|
||||||
[^2]: https://www.jianshu.com/p/a5514510f5b9?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
|
[^2]: https://www.jianshu.com/p/a5514510f5b9?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
|
||||||
[^3]: https://www.jianshu.com/p/0b68b992f688?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
|
[^3]: https://www.jianshu.com/p/0b68b992f688?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
|
||||||
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
''' mbinary
|
|
||||||
#########################################################################
|
|
||||||
# File : matrix-multiply.py
|
|
||||||
# Author: mbinary
|
|
||||||
# Mail: zhuheqin1@gmail.com
|
|
||||||
# Blog: https://mbinary.coding.me
|
|
||||||
# Github: https://github.com/mbinary
|
|
||||||
# Created Time: 2018-08-24 21:24
|
|
||||||
# Description:
|
|
||||||
#########################################################################
|
|
||||||
'''
|
|
||||||
|
|
||||||
def adjustOrd(sizes):
|
|
||||||
''' adjust the chain-multiply of matrix, sizes=[row1,row2,..,rown,coln]'''
|
|
||||||
n = len(sizes)
|
|
||||||
if n<3: return
|
|
32
dynamicProgramming/matrixChainMultiply.py
Normal file
32
dynamicProgramming/matrixChainMultiply.py
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
def matrixChainMultiply(seq):
|
||||||
|
'''matrix chain multiply, find the optimalest comb to multiply
|
||||||
|
eg ABCD, (AB)(CD), A((BC)D)
|
||||||
|
seq: sequence of matrix's scale, eg [A.row,A.col,B.col,C.col,D.col]
|
||||||
|
'''
|
||||||
|
print(seq)
|
||||||
|
n = len(seq)-1
|
||||||
|
mat = [[0]*n for i in range(n)]
|
||||||
|
mark = [[0]*n for i in range(n)]
|
||||||
|
for l in range(1,n):
|
||||||
|
for i in range(n):
|
||||||
|
j = i+l
|
||||||
|
if j>=n: continue
|
||||||
|
mat[i][j] = None
|
||||||
|
for k in range(i,j):
|
||||||
|
tmp = mat[i][k]+mat[k+1][j]+seq[i]*seq[k+1]*seq[j+1]
|
||||||
|
if mat[i][j] is None or mat[i][j]>tmp:
|
||||||
|
mark[i][j] = k
|
||||||
|
mat[i][j]= tmp
|
||||||
|
s= findSolution(mark,0,n-1)
|
||||||
|
print(s)
|
||||||
|
return mat[0][n-1]
|
||||||
|
def findSolution(mark,i,j):
|
||||||
|
if j==i: return 'M{}'.format(i+1)
|
||||||
|
if j-i==1: return 'M{} * M{}'.format(j,j+1)
|
||||||
|
k = mark[i][j]
|
||||||
|
return '('+findSolution(mark,i,k)+') * ('+findSolution(mark,k+1,j)+')'
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
seq = [5,10,3,12,5,50,6]
|
||||||
|
res = matrixChainMultiply(seq)
|
||||||
|
print(res)
|
52
math/arrangement.c
Normal file
52
math/arrangement.c
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#include<stdio.h>
|
||||||
|
|
||||||
|
void swap(int*arr,int i,int j)
|
||||||
|
{
|
||||||
|
int tmp;
|
||||||
|
tmp = arr[i];
|
||||||
|
arr[i] = arr[j];
|
||||||
|
arr[j] = tmp;
|
||||||
|
}
|
||||||
|
void nextArrangement(int *arr,int n)
|
||||||
|
{
|
||||||
|
if(arr[n-1]>arr[n-2]){
|
||||||
|
swap(arr,n-1,n-2);
|
||||||
|
}else{
|
||||||
|
int i;
|
||||||
|
for(i=n-1;i>0;--i){
|
||||||
|
if(arr[i]>arr[i-1])break;
|
||||||
|
}
|
||||||
|
if(i==0){//reverse arrangement, n,n-1,...,1
|
||||||
|
for(;i<n;++i)arr[i] = i;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
i=i-1;
|
||||||
|
for(int j=n-1;j>i;j--){
|
||||||
|
if(arr[j]>arr[i]){
|
||||||
|
int tmp = arr[j];
|
||||||
|
for(int k = j;k>i;--k)arr[k] = arr[k-1];
|
||||||
|
arr[i] =tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printArr(int *arr,int n)
|
||||||
|
{
|
||||||
|
for(int i=0;i<n;++i)printf("%d ",arr[i]);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int n = 4;
|
||||||
|
int a[n];
|
||||||
|
for(int i=0;i<n;++i)a[i]=i;
|
||||||
|
long long int fac=1;
|
||||||
|
for(int i=2;i<=n;++i)fac*=i;
|
||||||
|
for(int i=0;i<fac;++i){
|
||||||
|
printf("rank %d :",i);
|
||||||
|
printArr(a,n);
|
||||||
|
nextArrangement(a,n);
|
||||||
|
}
|
||||||
|
}
|
38
math/cantor.c
Normal file
38
math/cantor.c
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#include<stdio.h>
|
||||||
|
|
||||||
|
//使用康托展开计算全排列, 下面存储的是0!,1!,2!...(n-1)!
|
||||||
|
long long int fac[100]={};
|
||||||
|
void calFac(int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
fac[0]=1;
|
||||||
|
for(i=1;i<=n;i++){
|
||||||
|
fac[i]=i*fac[i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void getArrangement(int *arr,int n,int sum)
|
||||||
|
{
|
||||||
|
/*sum表示全排列由小到大排序后的名次,从0 开始计数, 由名次求出 n位的排列存储到 arr 中*/
|
||||||
|
int i,j,ct=0,k, ct2;
|
||||||
|
int flag[n];
|
||||||
|
for(i=0;i<n;i++)flag[i]=1;
|
||||||
|
|
||||||
|
for(i=n-1;i>=0;i--){
|
||||||
|
for(j=i;j>=0;j--){
|
||||||
|
if(j*fac[i]<=sum){
|
||||||
|
ct2=0;
|
||||||
|
for(k=0;k<n;++k){
|
||||||
|
//printf("i%d j%d k%d\n",i,j,k);
|
||||||
|
if(flag[k]==1)ct2++;
|
||||||
|
if(ct2>j)break;
|
||||||
|
}
|
||||||
|
arr[ct++] = k;
|
||||||
|
flag[k]=0;
|
||||||
|
sum -=j*fac[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
/* mbinary
|
|
||||||
#########################################################################
|
|
||||||
# File : cantor.cc
|
|
||||||
# Author: mbinary
|
|
||||||
# Mail: zhuheqin1@gmail.com
|
|
||||||
# Blog: https://mbinary.coding.me
|
|
||||||
# Github: https://github.com/mbinary
|
|
||||||
# Created Time: 2018-05-19 23:06
|
|
||||||
# Description:
|
|
||||||
#########################################################################
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include<iostream>
|
|
||||||
#include<stdio.h>
|
|
||||||
using namespace std;
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
float f;
|
|
||||||
while(cin.peek()!='E'){
|
|
||||||
cin>>f;
|
|
||||||
getchar();
|
|
||||||
bool flag=true;
|
|
||||||
for(int i=0;i<50&&(f-0.0000001)>0;++i){
|
|
||||||
int t=3*f;
|
|
||||||
f=3*f-t;
|
|
||||||
cout<<f<<endl;
|
|
||||||
if(t==1){
|
|
||||||
cout<<"NON-MEMBER"<<endl;
|
|
||||||
flag = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(flag)cout<<"MEMBER"<<endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
23
search/bloomFilter.py
Normal file
23
search/bloomFilter.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
from bitarray import bitarray
|
||||||
|
|
||||||
|
import mmh3
|
||||||
|
|
||||||
|
class bloomFilter(set):
|
||||||
|
def __init__(self,size,hash_count):
|
||||||
|
super(bloomFilter,self).__init__()
|
||||||
|
self.bits = bitarray(size)
|
||||||
|
self.bits.setall(0)
|
||||||
|
self.size = size
|
||||||
|
self.hash_count = hash_count
|
||||||
|
def __len__(self):
|
||||||
|
return self.size
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self.bits)
|
||||||
|
def add(self,item):
|
||||||
|
for i in range(self.hash_count):
|
||||||
|
idx = mmh3.hash(item,i) % self.size
|
||||||
|
self.bits[idx]=1
|
||||||
|
return self
|
||||||
|
def __contains__(self,item):
|
||||||
|
idxs = [mmh3.hash(item,i)%self.size for i in range(self.hash_count)]
|
||||||
|
return all([self.bits[i]==1 for i in idxs])
|
Loading…
Reference in New Issue
Block a user