# Data structure inside python

One. concept

When the program uses data structure to process data, how to organize and save the rose stone in memory? Please note that the data stored on disk as part of permanent storage (such as relational table) cannot be called data structure here. An algorithm is a set of instructions that process data for a specific purpose step by step. Therefore, the algorithm logically uses various data structures to solve specific computing problems.

Data structure is a basic concept of computer science. Here we learn about some common concepts of data structures and their relationship with some python data types. There are also python specific data structures that will become another category.

II. General data structure

1. Linear data structure (data structure that stores data elements in a sequential manner)

```         Array (index), linked list (link to another element and its data), stack( LIFO(Last in first out), FILO(fifo))

Queue( FIFO(fifo))，     Matrix (two-dimensional data structure in which data elements are referenced by a pair of indexes)
```

2. Nonlinear data structure (there is no sequential connection of data elements in the data structure, any pair or group of data can be related to each other, and can be accessed without strict number order)

```         Binary tree::It is a data structure, and each data element can be connected to up to two other data elements, starting with a root node.

Heap: This is a special case of tree data structure, in which the data in the parent node is strictly greater than/Equal to or strictly less than its children.

Hash table: it is a data structure consisting of arrays associated with each other using hash functions. It uses keys instead of indexes of data elements to retrieve values

Figure: it is a sort of fixed points and nodes, some of which are connected to each other through links
```

Python specific data structures

These data structures are unique to the python language. They can store different types of data more flexibly and process faster in the python environment.

List: it is similar to an array except that data elements can have different data types. You can include both numeric and string data in a Python list.

Tuples: tuples are similar to lists, but they are immutable, which means that the values in tuples cannot be modified, so they can only be read.

Dictionary: this dictionary contains key value pairs as its data elements.

3, Array (it is a container. Note that compared with the list in python, it can be declared in different languages. The index starts from 0. The array length and each element can be accessed through the index). It can accommodate a certain number of items. These items are of the same type. Most data structures use arrays to implement their algorithms.

1. Basic operation

Traversal, insert, delete, search, update

2. Implementation of array in Python language

```from array import *
#b/B/c/i/I/f/d
#1-byte signed integer / 1-byte unsigned integer / 1-byte character / 2-byte signed integer / 2-byte unsigned integer / 4-byte floating point number / 8-byte floating point number
arrayName=array('i',[10,20,30,40,50])
for i in arrayName:
print(i)

#Accessing array elements
array1=arrayName
print(array1)
print(array1)
#insert operation

array1.insert(0,20)
for i in array1:
print(i)

#Delete element
array1.remove(40)

#Find / search operation
print(array1.index(20))
#If the value is no longer in the array, an error is returned

#to update
array1=30
```

4, List (items in the list do not have to be of the same type) square brackets, and the index starts from 0

1. Access element: []

2. Update: you can update one or more elements of the list by giving slices to the left of the assignment operator, and you can add them to the elements in the list using the append() method

3. Delete element: del list1

4. Repeat: *+

Lists respond to the + and * operators much like strings; they also mean concatenation and repetition, but it evaluates to a new list, not a string. 5, Yuanzu: () index starts from 0

1. Access element: [] slice

2. Change ancestor: tuples are immutable, which means that the value of tuple elements cannot be updated or changed. However, part of existing tuples can be created or reorganized into new tuples

3. Delete element: it is impossible to delete a single tuple element; delete the whole element - del tup

4. Basic operation of elements 6, Dictionary (each key and value are separated by colon, and each item is separated by (,); the whole dictionary data is enclosed in curly braces; if an empty dictionary is {}; the key is unique in the dictionary, and the value may not be unique. The value of the dictionary can be of any type, but the key must be of immutable type)

1. Access operation: [] if you try to access a data item using a key that does not belong to the dictionary, you will get an error

2. Update dictionary elements; (add - [])

3. Delete dictionary element: del (the dictionary no longer exists) dict.clear() clears the dictionary. The dictionary exists but is empty

Note: the key cannot have the same name. If the key has the same name, the latter will overwrite the previous one; the key must be immutable

7, Two dimensional array (it is an array of arrays. In this type of array, the position of data elements is referenced by two indexes instead of one index. It is a table containing row and column data, and each array element in the two-dimensional array is also an array)

```from array import *
T=[[1,2,3,4],[5,6,7,8],[9,12,13,14],[8,7,6,5]]
#Two indexes are used to access the data elements in a two-dimensional array. One index refers to the main array or parent array, and the other index refers to the location of the data elements in the internal array
#If only one index is used, Jiang Wei will print internal data at that index position
print(T)
print(T)

#You can use the for loop to print the entire two-dimensional array, and use the end of the line to print the values in different lines

for r in T:
for c in r:
print(c,end=" ")
print()

#Inserting values into a two-dimensional array
T.insert(2,[0,5,11,13,6])

#Update the values in the two-dimensional array and use array index recopy to update the internal array or some specific data elements of the internal array
T=[11,9]
T=7
print('-------------------------------------------')

for r in T:
for i in r:
print(i,end=' ')
print()

#Delete values from a 2D array
del T
print('---------------------------------------')
for r in T:
for i in r:
print(i,end=' ')
print()
```
```#Operation results
F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
[1, 2, 3, 4]
7
1 2 3 4
5 6 7 8
9 12 13 14
8 7 6 5
-------------------------------------------
1 2 3 7
5 6 7 8
11 9
9 12 13 14
8 7 6 5
---------------------------------------
2 3 7
5 6 7 8
11 9
9 12 13 14
8 7 6 5
```

8, Collection (data items not in any particular order)

Elements in the collection cannot be duplicated.
The elements in the collection are immutable (cannot be modified), but the collection as a whole is mutable.
Any element attached to a python collection does not require an index. Therefore, the collection does not support any indexing or slicing operations

1. Create: Example

Days=set(["Mon","Tue","Wed","Thu","Fri","Sat","Sun"])
When you print a collection, the order of elements changes

2. Access the elements in the collection

You cannot access a single element of a collection. You can only access multiple elements, but you can print a list of individual elements by traversing

4. Delete the element discard('element value ')

5. Joint operation of sets AllDays=DayA|DaysB a new set containing all different elements from the two sets

6. Intersection of sets

```AllDays = DaysA & DaysB
```

7. Difference set

```AllDays = DaysA - DaysB
```

#8. Comparison set

```SubsetRes = DaysA <= DaysB
SupersetRes = DaysB >= DaysA
```

9, Matrix

```from array import *
T = [[11, 12, 5, 2], [15, 6,10], [10, 8, 12, 5], [12,15,8,6]]
print(type(T))
array1=array('b', [15, 6,10])
print(type(array1))

import numpy as np
shuzu=np.arange(20)
x=shuzu.reshape(5,4)
print(x)
print('--------------------------------------------------')
print(np.mean(x,axis=1))#1 representative bank
#delete
print('Delete the second column:')
print(np.delete(x,1,axis=1))#The element with index 1 of all rows and the element of the first column
print(x)
'''
Access mode
List:[][]
Array:[][]
Matrix:[][]
'''
```

Ten. python node

In some cases, the memory allocation for storing data cannot be located in consecutive memory blocks. Therefore, with the help of pointers, the data and the address of the next position of the data element are also stored. Therefore, the address of the next data element is known from the value of the current data element. Usually such a structure is called a pointer. But in Python, they are called nodes.

Nodes are the basis for the processing of various other data structures, linked lists and trees in python

```class daynames:
def __init__(self,dataval=None):
self.dataval=dataval
self.nextval=None

e1=daynames('Mon')
e2=daynames('Tue')
e3=daynames('Wed')

e1.nextval=e3
e3.nextval=e2
```

2. Traversal of node elements

```class daynames:
def __init__(self, dataval=None):
self.dataval = dataval
self.nextval = None

e1 = daynames('Mon')
e2 = daynames('Tue')
e3 = daynames('Wed')

e1.nextval = e3
e3.nextval = e2

thisvalue=e1
while thisvalue:
print(thisvalue.dataval)
thisvalue=thisvalue.nextval
```
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
Mon
Wed
Tue

Process finished with exit code 0
```

Eleven. python linked list (single linked list)

1. Create linked list

```#establish
class Node:
def __init__(self,dataval=None):
self.dataval=dataval
self.nextval=None

def __init__(self):

#Traversal method
def listprint(self):
while printval is not None:
print(printval.dataval)
printval =printval.nextval

#Insert at the beginning of the list
def AtBegining(self,newdata):
NewNode = Node(newdata)
#Inserts a node at the end of the list
def AtEnd(self,newdata):
NewNode = Node(newdata)
if self.headval is None:
return
#I think this is the essence.
while(laste.nextval):
laste=laste.nextval
laste.nextval=NewNode

def Inbetween(self,middle_node,newdata):
if middle_node is None:
print("the mentioned node is absent")
return
NewNode = Node(newdata)
NewNode.nextval=middle_node.nextval
middle_node.nextval = NewNode

e2=Node('heTue')
e3=Node('Wed')
e2.nextval=e3

#ergodic
list1.listprint()

#Insert node in header
list1.AtBegining("sum")
print('--------------------------')
list1.listprint()

print('-------------------------------------------')
#Insert node at tail
list1.AtEnd('Thu')
list1.listprint()

print('-----------------------------------')
#Insert in the middle
list1.Inbetween(e2,"Fri")
list1.listprint()
```
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
Mon
heTue
Wed
--------------------------
sum
Mon
heTue
Wed
-------------------------------------------
sum
Mon
heTue
Wed
Thu
-----------------------------------
sum
Mon
heTue
Fri
Wed
Thu
```

2. Delete elements from the linked list

#Delete a node from the linked list
#You can use the key of the node to delete a node. In the following program, find the previous node of the node to be deleted, and then point the next pointer of the node to the next node of the node to be deleted

```class Node:
def __init__(self, data=None):
self.data = data
self.next = None

def __init__(self):

def Atbegining(self, data_in):
NewNode = Node(data_in)
#Key points

#Function to remove node
#What happens to be deleted is the first one
def RemoveNode(self, Removekey):
if (headVal is not None):
return
#Not the first case
while(headVal is not None):
if headVal.data == Removekey:
break
if (headVal == None):
return
#After finding which node, the next node of the previous node points to the next node to be deleted, and the value of the node to be deleted is null

def LListprint(self):
while (printval):
print(printval.data),
printval = printval.next

list1.Atbegining('Mon')
list1.Atbegining('Tue')
list1.Atbegining('Wed')
list1.Atbegining('The')
list1.RemoveNode('Tue')
list1.LListprint()
```
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
The
Wed
Mon

Process finished with exit code 0
```

Twelve. Pile (enter from that end and exit from that end)

Indicates that the object is placed on another object, and the way of allocating memory in this data structure is the same. It stores array elements in a similar way, similar to piles of plates in the kitchen, one on top of the other, so the end of the stack data structure that allows operations can be called the top of the stack, and elements can be added to the top of the stack or only removed from the stack.

The last element in order in the stack will appear first because it can only be removed from the top of the stack. This operation is called last in first out. The operations of adding and deleting elements are called PUSH and POP. In the following program, we implement them as add and remove functions. First declare an empty list and use the append() and pop() methods to add and remove data elements.

```class Stack:

def __init__(self):
self.stack = []

if dataval not in self.stack:
#Add from the tail, and then add the latter one
self.stack.append(dataval)
return True
else:
return False

#Delete, LIFO
def remove(self):
if len(self.stack) <=0:
return ('no slement in the stack')
else:
return self.stack.pop()

def peek(self):
return self.stack

Astack = Stack()
print(Astack.peek())
print(Astack.remove())
```
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
Mon
The

Process finished with exit code 0
```

Twelve. Queue (in from one end and out from the other)

I am familiar with queuing in daily life. Queue structure also means that data elements are arranged in a queue. The uniqueness of a queue depends on how items are added and deleted. These objects can be placed last but removed from the other end, so this is a first in, first out method. Queues can be implemented using python list, and elements can be added and removed using insert() and pop() methods. They are not inserted because data elements are always added at the end of the queue.

```class Queue:
def __init__(self):
self.queue = list()

if dataval not in self.queue:
self.queue.insert(0,dataval)
return True
return False

def removefromq(self):
if len(self.queue) > 0:
return self.queue.pop()
return ('No element in Queue!')

def size(self):
return len(self.queue)

TheQueue = Queue()
print(TheQueue.size())
print(TheQueue.removefromq())
print(TheQueue.removefromq())
```
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
3
Mon
Tue

Process finished with exit code 0
```

Thirteen. python double ended queue

Double ended queues (or double ended queues) have the ability to add and delete elements from either end. The Deque module is part of the collection library and has methods to add and delete elements that can be called directly with parameters. In the following program, you will import the collections module and declare a double ended queue. You don't need any classes to implement these methods directly using the built-in.

```import collections

#Create a deque
DoubleEnded = collections.deque(["Mon","Tue","Wed"])

#append to the right
print('Adding to the right:')
DoubleEnded.append("Thu")
print(DoubleEnded)

#append to the left
print('adding to the left')
DoubleEnded.appendleft('Sun')
print(DoubleEnded)

#Remove from the right
print("Removing from the right")
DoubleEnded.pop()
print(DoubleEnded)

#Remove from the left
print("Removing from the left:")
DoubleEnded.popleft()
print(DoubleEnded)

#Reverse the dequeue
print("reverse the deque:")
DoubleEnded.reverse()
print(DoubleEnded)
```
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
Adding to the right:
deque(['Mon', 'Tue', 'Wed', 'Thu'])
adding to the left
deque(['Sun', 'Mon', 'Tue', 'Wed', 'Thu'])
Removing from the right
deque(['Sun', 'Mon', 'Tue', 'Wed'])
Removing from the left:
deque(['Mon', 'Tue', 'Wed'])
reverse the deque:
deque(['Wed', 'Tue', 'Mon'])

Process finished with exit code 0
```

We see another list of links that can be moved forward and backward. This kind of linked list is called bidirectional linked list. The following are the characteristics of a two-way linked list.

1. The two-way linked list contains the first and last link elements

2. Each connection has a numeric field and two link fields called next and prev

5. The last link marks the end of the list as empty

'''
To create a two-way linked list, we use the Node class to create a double linked list. Using the same method as in the single linked list,
However, in addition to the data that exists in the node, the header pointer and the next pointer will be used for proper allocation to create two links in each node.
'''

```class Node:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None

def __init__(self):

def push(self,NewVal):
NewNode = Node(NewVal)
if self.head is not None:

#define the insert method to insert the element
def insert(self,prev_node,NewVal):
if prev_node is None:
return
#Note that this link goes through 4 (1. The next node of the new node points to the next node of the previous node. 2. The next node of the previous node points to the new node. 3. The previous node of the new node points to the previous node. 4. The previous node of the next node of the previous node points to the new node)
NewNode = Node(NewVal)
NewNode.next = prev_node.next
prev_node.next = NewNode
NewNode.prev = prev_node
if NewNode.next is not None:
NewNode.next.prev = NewNode

#define the append method to add element at the end
def append(self, NewVal):
NewNode = Node(NewVal)
NewNode.next = None
if self.head is None:
NewNode.prev = None
return

while (last.next is not None):
last = last.next
last.next = NewNode
NewNode.prey = last

#print the doubly linked list
def listprint(self, node):
while(node is not None):
print(node.data)
last = node
node = node.next

dlist.push(12)
dlist.push(8)
dlist.push(62)

dlist.append('30')
```
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
62
8
12
62
8
12
13
30

Process finished with exit code 0
``` Fifteen. Hashtable

Hash table (also known as hash table) is a data structure whose address or index value of data element is generated by hash function. This makes accessing data faster. Because the index value is the key of the data value. In other words, the hash table stores key value pairs, but the keys are born through the hash function. Therefore, the search and insert functions of data elements become faster, because the key value itself becomes the index of the array in which the data is stored.

In python, the dictionary data type represents the implementation of a hash table. The keys in the dictionary meet the following requirements

1. The key of the dictionary is hashable, that is, the hash function is generated through the hash function, which generates a unique result for each unique value provided to the hash function

2. The order of data elements in the dictionary is not fixed

Access value [] in dictionary

Update dictionary elements

Delete dictionary element del can delete a single dictionary element or clear all the contents of the dictionary. You can also delete the entire dictionary in one operation. To explicitly delete the entire dictionary, simply use the Del statement dict.clear()

Sixteen. Number of python searches

A binary search tree (BST) is a tree in which all nodes follow the following attribute - the key of the left child tree of a node is less than or equal to the key of its parent node. The key of the right subtree of a node is greater than that of its parent node. Therefore, BST divides all its subtrees into two parts, the subtree on the left and the subtree on the right

```left_subtree (keys)  ≤  node (key)  ≤  right_subtree (keys)
```

'''
Searching for values in the B-tree searching for values in the tree involves comparing the input value with the value of the exit node.
Here, the node is traversed from left to right, and finally the parent node.
If the searched value does not match any exit value, the message not found is returned; otherwise, the message found is returned.
'''

```class Node:
def __init__(self,data):
self.left = None
self.right = None
self.data = data

#Insert method to create nodes
def insert(self,data):

if self.data:
if data<self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data

#findval method to compare the value with nodes
def findval(self,lkpval):
if lkpval < self.data:
if self.left is None:
return self.left.findval(lkpval)
elif lkpval > self.data:
if self.right is None:
return self.right.findval(lkpval)
else:
print(str(self.data)+' is found')

def PrintTree(self):
if self.left:
self.left.PrintTree()
print(self.data)
if self.right:
self.right.PrintTree()

root = Node(12)
root.insert(6)
root.insert(14)
root.insert(3)
print(root.findval(7))
print(root.findval(14))
```
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
14 is found
None

Process finished with exit code 0
```

Seventeen. python heap

Heap is a special tree structure in which each parent node is less than or equal to its child nodes. Then it is called min heap. If each parent node is greater than or equal to its child nodes. It is called max heap. It is very useful to implement priority queue, in which queue items with higher weight have higher priority in processing.

1. Create a heap by using a library named heapq built in python. The library has the related functions of various operations on the heap data structure.

heapify converts a regular class table into a heap. In the result heap, the smallest element is pushed to index position 0, but the remaining elements are not necessarily sorted.

heappush this function adds an element to the heap without changing the current heap.

heappop this function returns the smallest data element

Heappreplace this function replaces the smallest data element with the new value provided in the function (delete the smallest, push forward the rest, and fill in the content to be replaced)

Create the heap by simply using the list of elements with the heapify function.

```import heapq
H=[21,1,45,78,3,5]
#Create a heap
heapq.heapify(H)
print(H)
#Insert heap
'''Inserting data elements into the heap is always added at the last index. However, it can be applied again only when the value is the smallest heapify Function adds the newly added element to the first.'''
heapq.heappush(H,8)
print(H)
#Remove from heap
'''You can use this function to an element at the first index,'''
heapq.heappop(H)
print(H)

#Replace heap
'''heapreplace The function always deletes the smallest element in the stack and inserts a new incoming element where it has not been repaired in any order'''
heapq.heapreplace(H,6)
print(H)
```
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
[1, 3, 5, 78, 21, 45]
[1, 3, 5, 78, 21, 45, 8]
[3, 8, 5, 78, 21, 45]
[5, 8, 6, 78, 21, 45]
```

Eighteen. chart

A graph is a graphical representation of a set of objects linked by links. Interconnected objects are represented by points called fixed points, and links connecting fixed points are called edges.

1. Basic operation

Show shape vertices

Show drawing edges

Create a graph

You can easily render diagrams using python dictionary data structure types. We represent vertices as dictionary keywords, and the links between vertices become boundaries as values in the dictionary

In the figure above

```V={a,b,c,d,e}

E={ab,ac,bd,cd,de}

use python Implement this diagram

#create the dictionary eith graph elements
graph = {
"a":["b","c"],
"b":["a","d"],
"c":["a","d"],
"d":["e"],
"e":["d"]

}
print(graph)
```
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
{'a': ['b', 'c'], 'b': ['a', 'd'], 'c': ['a', 'd'], 'd': ['e'], 'e': ['d']}

Process finished with exit code 0
```

2. Display the vertices of the graph

To display the vertices of the graph, simply find the keywords of the graph dictionary and use the keys() method

```class graph:
def __init__(self,gdict=None):
if gdict is None:
gdict = []
self.gdict = gdict

#get the keys of the dictionary
def getVertices(self):
return list(self.gdict.keys())

#create the dictionary with graph elements
graph_elements ={ "a" : ["b","c"],
"b" : ["a", "d"],
"c" : ["a", "d"],
"d" : ["e"],
"e" : ["d"]
}
g=graph(graph_elements)
print(g.getVertices())
```
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
['a', 'b', 'c', 'd', 'e']

Process finished with exit code 0
```

Show the edges of the diagram (later understood)

Finding graph edges is less than vertices, because you must find vertices with one edge between each pair of vertices. Therefore, create an empty list of edges, and then iterate over the edge values associated with each vertex. A list forms edges that contain different groups of edges found from vertices.

[{'a', 'b'}, {'c', 'a'}, {'d', 'b'}, {'c', 'd'}, {'d', 'e'}]

```class graph:
def __init__(self,gdict=None):
if gdict is None:
gdict = []
self.gdict = gdict

#get the keys of the dictionary
def getVertices(self):
return list(self.gdict.keys())
#add the vertex as a key
if vrtx not in self.gdict:
self.gdict[vrtx] = []

#create the dictionary with graph elements
graph_elements ={ "a" : ["b","c"],
"b" : ["a", "d"],
"c" : ["a", "d"],
"d" : ["e"],
"e" : ["d"]
}
g=graph(graph_elements)
print(g.getVertices())
print(g.getVertices())
```
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py
['a', 'b', 'c', 'd', 'e']
['a', 'b', 'c', 'd', 'e', 'f']

Process finished with exit code 0
```

Adding an edge to an existing graph involves treating the new vertex as a tuple and verifying that the edge already exists. If it does not exist, add an edge

```class graph:
def __init__(self,gdict=None):
if gdict is None:
gdict = {}
self.gdict = gdict
def edges(self):
return self.findedges()

#add the new edge
#The so-called adding edge is to abstract the number into the form of a dictionary
edge = set(edge)
(vrtx1,vrtx2) = tuple(edge)
if vrtx1 in self.gdict:
self.gdict[vrtx1].append(vrtx2)
else:
self.gdict[vrtx1] = [vrtx2]

#list the edge names
#The combination of printing edge, {key: value} is an edge
def findedges(self):
edgename = []
for vrtx in self.gdict:
for nxtvrtx in self.gdict[vrtx]:
#key
if {nxtvrtx,vrtx} not in edgename:
edgename.append({vrtx,nxtvrtx})
return edgename

# Create the dictionary with graph elements
graph_elements = { "a" : ["b","c"],
"b" : ["a", "d"],
"c" : ["a", "d"],
"d" : ["e"],
"e" : ["d"]
}
g = graph(graph_elements)
```F:\7-9 Practice code\fuxi\venv\Scripts\python.exe F:/7-9 Practice code/fuxi/shujujiegou.py