from
tkinter
import
Tk, ttk, font
from
tkinter
import
*
Width
=
1200
Height
=
700
col_0
=
120
row_0
=
40
row_1
=
70
class
node():
def
__init__(
self
, value
=
0
, left
=
None
, right
=
None
, pre
=
None
):
self
.value
=
value
self
.left
=
left
self
.right
=
right
self
.r_height
=
0
self
.l_height
=
0
self
.pre
=
pre
class
link():
def
__init__(
self
, value):
self
.head
=
node(value)
self
.length
=
0
def
T_adj(
self
, the_node):
p
=
the_node
if
p
is
not
None
:
x
=
p.value
if
abs
(p.l_height
-
p.r_height) >
=
2
:
self
.adj(p)
return
self
.T_adj(p.pre)
return
def
adj(
self
, the_node):
p
=
the_node
if
p.l_height
-
p.r_height >
=
2
:
if
p.left.right
is
None
:
self
.r_rotate(p)
else
:
if
p.left.left
is
not
None
:
self
.r_rotate(p)
else
:
self
.l_rotate(p.left)
self
.r_rotate(p)
if
p.r_height
-
p.l_height >
=
2
:
if
p.right.left
is
None
:
self
.l_rotate(p)
else
:
if
p.right.right
is
not
None
:
self
.l_rotate(p)
else
:
self
.r_rotate(p.right)
self
.l_rotate(p)
def
search(
self
, value, the_node):
p
=
the_node
if
value > p.value:
if
p.right
is
not
None
:
x
=
self
.search(value, p.right)
try
:
p.r_height
=
max
(x.l_height, x.r_height)
+
1
self
.update_height2(p)
self
.T_adj(p)
except
:
pass
else
:
temp
=
node(value
=
value, pre
=
p)
p.right
=
temp
p.r_height
=
1
return
p
elif
value < p.value:
if
p.left
is
not
None
:
x
=
self
.search(value, p.left)
try
:
p.l_height
=
max
(x.l_height, x.r_height)
+
1
self
.update_height2(p)
self
.T_adj(p)
except
:
pass
else
:
temp
=
node(value
=
value, pre
=
p)
p.left
=
temp
p.l_height
=
1
return
p
def
add(
self
, value):
self
.search(value,
self
.head)
self
.length
+
=
1
def
show_all(
self
):
print
(
'===========开始=============='
)
p
=
self
.head
queue
=
[p]
while
len
(queue) !
=
0
:
x
=
queue.pop(
0
)
print
(x.value, x.l_height, x.r_height)
if
x.left
is
not
None
:
queue.append(x.left)
if
x.right
is
not
None
:
queue.append(x.right)
print
(
'==========结束==============='
)
def
find(
self
, key, the_node, direction
=
''):
p
=
the_node
if
key
=
=
p.value:
return
p, direction
elif
p.value < key:
if
p.right
is
not
None
:
return
self
.find(key, p.right,
'right'
)
else
:
if
p.left
is
not
None
:
return
self
.find(key, p.left,
'left'
)
def
find_min(
self
, the_node):
if
the_node.left
is
not
None
:
return
self
.find_min(the_node.left)
else
:
return
the_node
def
find_max(
self
, the_node):
if
the_node.right
is
not
None
:
return
self
.find_max(the_node.right)
else
:
return
the_node
def
update_height2(
self
, the_node):
p
=
the_node
if
p
is
not
None
:
if
p.left
is
not
None
and
p.right
is
not
None
:
p.l_height
=
max
(p.left.l_height,
p.left.r_height)
+
1
p.r_height
=
max
(p.right.l_height,
p.right.r_height)
+
1
elif
p.left
is
not
None
and
p.right
is
None
:
p.r_height
=
0
p.l_height
=
max
(p.left.l_height,
p.left.r_height)
+
1
elif
p.left
is
None
and
p.right
is
not
None
:
p.r_height
=
max
(p.right.l_height,
p.right.r_height)
+
1
p.l_height
=
0
else
:
p.r_height
=
0
p.l_height
=
0
self
.update_height2(p.pre)
return
p
def
update_height(
self
, the_node):
if
the_node.left
is
not
None
and
the_node.right
is
not
None
:
the_node.l_height
=
max
(
self
.update_height(the_node.left).l_height,
self
.update_height(the_node.left).r_height)
+
1
the_node.r_height
=
max
(
self
.update_height(the_node.right).l_height,
self
.update_height(the_node.right).r_height)
+
1
elif
the_node.left
is
not
None
and
the_node.right
is
None
:
the_node.r_height
=
0
the_node.l_height
=
max
(
self
.update_height(the_node.left).l_height,
self
.update_height(the_node.left).r_height)
+
1
elif
the_node.left
is
None
and
the_node.right
is
not
None
:
the_node.r_height
=
max
(
self
.update_height(the_node.right).l_height,
self
.update_height(the_node.right).r_height)
+
1
the_node.l_height
=
0
else
:
the_node.r_height
=
0
the_node.l_height
=
0
return
the_node
def
remove(
self
, key):
the_node, direction
=
self
.find(key,
self
.head)
if
the_node.left
is
not
None
:
replace_max
=
self
.find_max(the_node.left)
else
:
replace_max
=
self
.find_max(the_node)
if
the_node.right
is
not
None
:
replace_min
=
self
.find_min(the_node.right)
else
:
replace_min
=
self
.find_max(the_node)
if
replace_max.value
=
=
replace_min.value
=
=
the_node.value:
if
direction
=
=
'right'
:
the_node.pre.right
=
None
if
direction
=
=
'left'
:
the_node.pre.left
=
None
self
.update_height2(the_node.pre)
the_node
=
None
elif
replace_min.value !
=
the_node.value:
temp
=
replace_min
temp.pre.left
=
temp.right
self
.update_height2(temp.pre)
temp.right
=
the_node.right
temp.left
=
the_node.left
try
:
the_node.left.pre
=
temp
except
:
pass
try
:
the_node.right.pre
=
temp
except
:
pass
if
the_node.value
=
=
self
.head.value:
temp.pre
=
None
self
.head
=
temp
else
:
temp.pre
=
the_node.pre
if
direction
=
=
'right'
:
the_node.pre.right
=
temp
if
direction
=
=
'left'
:
the_node.pre.left
=
temp
self
.update_height2(temp)
self
.adj(temp)
the_node
=
None
elif
replace_max.value !
=
the_node.value:
temp
=
replace_max
temp.pre.right
=
temp.left
self
.update_height2(temp.pre)
temp.left
=
the_node.left
temp.right
=
the_node.right
try
:
the_node.left.pre
=
temp
except
:
pass
try
:
the_node.right.pre
=
temp
except
:
pass
if
the_node.value
=
=
self
.head.value:
temp.pre
=
None
self
.head
=
temp
else
:
temp.pre
=
the_node.pre
if
direction
=
=
'right'
:
the_node.pre.right
=
temp
if
direction
=
=
'left'
:
the_node.pre.left
=
temp
self
.update_height2(temp)
self
.adj(temp)
the_node
=
None
self
.length
-
=
1
def
l_rotate(
self
, the_node):
direction
=
self
.find(the_node.value,
self
.head)[
1
]
temp
=
the_node.right
the_node.right
=
temp.left
temp.pre
=
the_node.pre
temp.left
=
the_node
if
the_node.value
=
=
self
.head.value:
self
.head
=
temp
else
:
if
direction
=
=
'left'
:
the_node.pre.left
=
temp
else
:
the_node.pre.right
=
temp
the_node.pre
=
temp
if
the_node.right
is
not
None
:
the_node.r_height
=
max
(the_node.right.r_height, the_node.right.l_height)
+
1
else
:
the_node.r_height
=
0
self
.update_height2(temp)
def
r_rotate(
self
, the_node):
direction
=
self
.find(the_node.value,
self
.head)[
1
]
temp
=
the_node.left
the_node.left
=
temp.right
temp.pre
=
the_node.pre
temp.right
=
the_node
if
the_node.value
=
=
self
.head.value:
self
.head
=
temp
else
:
if
direction
=
=
'left'
:
the_node.pre.left
=
temp
else
:
the_node.pre.right
=
temp
the_node.pre
=
temp
if
the_node.left
is
not
None
:
the_node.l_height
=
max
(the_node.left.l_height, the_node.left.r_height)
+
1
else
:
the_node.l_height
=
0
self
.update_height2(temp)
def
clear_all(
self
):
self
.head
=
None
self
.length
-
=
self
.length
def
get_len(
self
):
return
self
.length
class
Window():
def
__init__(
self
):
self
.one_link
=
link(
0
)
self
.root
=
Tk()
self
.root.title(
'可视化AVL树-作者:lthero'
)
frame
=
Frame(
self
.root, width
=
Width
-
20
, height
=
Height
-
20
)
frame.grid(row
=
0
, column
=
0
)
self
.canvas
=
Canvas(frame, bg
=
'#FFFFFF'
, width
=
Width
-
20
, height
=
Height
-
20
, scrollregion
=
(
-
800
,
0
, Width
+
800
, Height
+
800
)) #
hbar
=
Scrollbar(frame, orient
=
HORIZONTAL)
hbar.pack(side
=
BOTTOM, fill
=
X)
hbar.config(command
=
self
.canvas.xview)
vbar
=
Scrollbar(frame, orient
=
VERTICAL)
vbar.pack(side
=
RIGHT, fill
=
Y)
vbar.config(command
=
self
.canvas.yview)
self
.canvas.config(xscrollcommand
=
hbar.
set
, yscrollcommand
=
vbar.
set
)
self
.canvas.pack(side
=
LEFT, expand
=
True
, fill
=
BOTH)
self
.input_label
=
ttk.Entry(
self
.root, font
=
font.Font(size
=
13
, weight
=
'bold'
), width
=
10
)
self
.input_label.place(x
=
10
, y
=
row_0
-
30
)
self
.input_label.focus_set()
self
.B_in
=
ttk.Button(
self
.root, text
=
'add it'
, command
=
self
.get_int, width
=
8
)
self
.B_in.place(x
=
col_0, y
=
row_0
-
30
)
self
.B_out
=
ttk.Button(
self
.root, text
=
'remove it'
, command
=
self
.delete, width
=
8
)
self
.B_out.place(x
=
col_0, y
=
row_1
-
30
)
self
.B_out
=
ttk.Button(
self
.root, text
=
'restart'
, command
=
self
.restart, width
=
8
)
self
.B_out.place(x
=
col_0
-
100
, y
=
row_1
-
30
)
self
.root.bind(
'<Return>'
,
self
.get_int)
self
.is_first
=
0
screenwidth
=
self
.root.winfo_screenwidth()
screenheight
=
self
.root.winfo_screenheight()
alignstr
=
'%dx%d+%d+%d'
%
(Width, Height, (screenwidth
-
Width)
/
2
, (screenheight
-
Height)
/
2
)
self
.root.geometry(alignstr)
def
about():
win2
=
Toplevel(
self
.root)
win2.title(
'关于'
)
width
=
280
height
=
200
screenwidth
=
self
.root.winfo_screenwidth()
screenheight
=
self
.root.winfo_screenheight()
alignstr2
=
'%dx%d+%d+%d'
%
(width, height, (screenwidth
-
width)
/
2
, (screenheight
-
height)
/
2
)
win2.geometry(alignstr2)
win2.resizable(width
=
False
, height
=
False
)
win2.focus_set()
Help
=
Label(win2, text
=
'可视化AVL树\n\n功能:可以添加,但删除有bug\n\n 完成于2021年4月21日,作者:lthero'
, font
=
(
'微软雅黑'
,
10
))
Help
.place(x
=
40
, y
=
40
)
menu
=
Menu(
self
.root, tearoff
=
False
)
Cmenu
=
Menu(menu, tearoff
=
False
)
Cmenu.add_command(label
=
'关于'
, command
=
about)
menu.add_cascade(label
=
'点我'
, menu
=
Cmenu)
self
.root.config(menu
=
menu)
self
.root.mainloop()
def
restart(
self
):
self
.one_link.clear_all()
self
.is_first
=
0
self
.draw_all()
self
.input_label.focus_set()
def
get_int(
self
,
*
args):
x
=
self
.input_label.get()
if
self
.is_first
=
=
0
:
if
x !
=
'':
self
.add_one(
int
(x),
1
)
self
.is_first
=
1
else
:
if
x !
=
'':
self
.add_one(
int
(x))
self
.input_label.delete(
0
,END)
self
.input_label.focus_set()
def
add_one(
self
, value, flag
=
0
):
if
flag
=
=
1
:
self
.one_link.head
=
node(value)
else
:
self
.one_link.add(value)
self
.show()
self
.draw_all()
def
delete(
self
):
x
=
self
.input_label.get()
self
.one_link.remove(
int
(x))
self
.input_label.delete(
0
,END)
self
.input_label.focus_set()
self
.show()
self
.draw_all()
def
show(
self
):
self
.one_link.show_all()
def
draw_one(
self
,the_node,x,y):
p
=
the_node
if
p
is
not
None
:
if
p.left
is
not
None
:
temp
=
max
(p.left.r_height, p.left.l_height)
pian
=
30
pian_y
=
1
if
temp>
=
2
:
pian
=
60
if
temp>
=
3
:
pian
=
80
pian_y
+
=
2
self
.canvas.create_line(x, y, x
-
30
-
temp
*
pian, y
+
35
*
pian_y)
self
.draw_one(p.left, x
-
30
-
temp
*
pian, y
+
35
*
pian_y)
if
p.right
is
not
None
:
temp
=
max
(p.right.l_height, p.right.r_height)
pian
=
30
pian_y
=
1
if
temp>
=
2
:
pian
=
60
if
temp>
=
3
:
pian
=
80
pian_y
+
=
2
self
.canvas.create_line(x, y, x
+
40
+
temp
*
pian, y
+
35
*
pian_y)
self
.draw_one(p.right, x
+
40
+
temp
*
pian, y
+
35
*
pian_y)
self
.canvas.create_oval(x
-
15
, y
-
15
, x
+
15
, y
+
15
, fill
=
'yellow'
)
self
.canvas.create_text(x, y, text
=
the_node.value)
else
:
return
def
draw_all(
self
):
x
=
450
y
=
50
if
self
.one_link.head
is
not
None
:
if
max
(
self
.one_link.head.r_height,
self
.one_link.head.l_height)>
=
3
:
x
+
=
150
self
.canvas.create_rectangle(
-
800
,
0
, Width
+
800
,Height
+
800
, fill
=
'white'
,width
=
0
)
self
.draw_one(
self
.one_link.head,x,y)
x
=
Window()