Python Development [Data Structure]: Foundation

Keywords: Python Lambda Programming

data structure

What is a data structure?

Simply put, data structure is to design how data is organized and stored in a computer.

Lists, collections and dictionaries are all data structures.

N.Wirth: "Program = Data Structure + Algorithms"

 

list

List: In other programming languages, called "arrays", is a basic data structure type.

Questions about lists:

  • How do the elements in the list be stored?
  • What basic operations does the list provide?
  • What is the time complexity of these operations?

 

Stack

Stack is a collection of data that can be understood as a list of insertions or deletions that can only be performed at one end.

Stack features:

  • last-in, first-out

The concept of stack:

  • Top of stack
  • Bottom of stack

The basic operation of the stack:

  • Stack (stack): push
  • Stack: pop
  • Take the top of the stack: gettop

Pictured:

Python implementation of stack:

You don't need to define it yourself, just use the list structure.
Stack function: append
 Out-of-stack function: pop
 Look at the top stack function: li[-1]

 

Application of stack - bracket matching problem:

Bracket matching problem: Give a string, which contains parentheses, middle parentheses, braces, to find whether the brackets in the string match.

For example:

()() () []{} matching
 ([{()}]) Matching
 [] (mismatch)
[(]) Mismatch

Code:

def cheak_kuohao(s):
    stack = []
    for char in s:
        if char in {'(','[', '{'}:
            stack.append(char)
        elif char == ')':
            if len(stack)>0 and stack[-1]=='(':
                stack.pop()
            else:
                return False
        elif char == ']':
            if len(stack) > 0 and stack[-1] == '[':
                stack.pop()
            else:
                return False
        elif char == '}':
            if len(stack)>0 and stack[-1]=='{':
                stack.pop()
            else:
                return False
    if len(stack) == 0:
        return True
    else:
        return False


print(cheak_kuohao('()[]{{[]}}'))
# True

 

The application of stack-maze problem:

Give a two-dimensional list of mazes (0 for channels, 1 for walls). Give an algorithm to find a way out of the maze

Solutions:

On a maze node (x,y), four directions can be explored: maze [x-1] [y], maze [x+1] [y], maze [x] [y-1], maze [x] [y-1], maze [x] [y+1]
Idea: Start from a node, arbitrarily find the next point to go, when you can not find the point to go, go back to the last point to find whether there are other directions.
Method: Create an empty stack, first put the entry position into the stack. When the stack is not empty, loop: get the top element of the stack, look for the next travelable adjacent square. If you can't find the next travelable adjacent square, it shows that the current position is a dead end, and go back (that is, the current position is out of the stack, see if there is another way out of the front point).

Solution code:

maze = [
    [1,1,1,1,1,1,1,1,1,1],
    [1,0,0,1,0,0,0,1,0,1],
    [1,0,0,1,0,0,0,1,0,1],
    [1,0,0,0,0,1,1,0,0,1],
    [1,0,1,1,1,0,0,0,0,1],
    [1,0,0,0,1,0,0,0,0,1],
    [1,0,1,0,0,0,1,0,0,1],
    [1,0,1,1,1,0,1,1,0,1],
    [1,1,0,0,0,0,0,1,0,1],
    [1,1,1,1,1,1,1,1,1,1]
]

dirs = [lambda x, y: (x + 1, y),
        lambda x, y: (x - 1, y),
        lambda x, y: (x, y - 1),
        lambda x, y: (x, y + 1)]

def mpath(x1, y1, x2, y2):
    stack = []
    stack.append((x1, y1))
    while len(stack) > 0:
        curNode = stack[-1]
        if curNode[0] == x2 and curNode[1] == y2:
            #Reach the finish line
            for p in stack:
                print(p)
            return True
        for dir in dirs:
            nextNode = dir(curNode[0], curNode[1])
            if maze[nextNode[0]][nextNode[1]] == 0:
                #Find the next one
                stack.append(nextNode)
                maze[nextNode[0]][nextNode[1]] = -1  # Mark as past to prevent dead cycles
                break
        else:#Four directions were not found.
            maze[curNode[0]][curNode[1]] = -1  # A dead end. Don't go next time.
            stack.pop() #To flash back
    print("No road")
    return False

mpath(1,1,8,8)

 

queue

Queue is a data set that allows insertion only at one end of the list and deletion at the other end.

The end of the insertion is called rear, and the insertion action is called entry or entry.

The end of the deletion is called the front, and the deletion action is called out of the team.

The nature of the queue:

  • First-in, First-out

Two-way queue:

  • Entry and exit operations are allowed at both ends of the queue

Can queues be simply implemented in lists? Why?

Preliminary assumption: list + two subscript pointers

Create a list and two variables, the front variable points to the head of the queue, and the rear variable points to the end of the queue.

Initially, both front and rear are 0.

Entry operation: The element is written to the position of li[rear], rear increases by 1.

Out-of-line operation: Returns the element of li[front], and the front decreases by 1.

The question of this realization? (No, it takes time or memory)

Improvement: Logically connect the beginning and end of the list

1 ring queue: When the end of the queue pointer front = Maxsize + 1, another forward position automatically goes to 0.
2. Implementation: Residual arithmetic
 3 Team Head Pointer Forward 1:front = front + 1% MaxSize
 Four trailing pointers forward 1:rear = rear + 1% MaxSize
 5 Team Air Conditions: rear = front
 6 Teams Full Conditions: (rear + 1)% MaxSize = front
Ring queue implementation

python usage: (from collections import deque)

Create queues: queue = deque(li)
Entry: append
 Team formation: popleft
 The first two-way queue: appendleft
 Two-way queue at the end of the queue: pop

 

Application of Queue-Maze Problem

Solutions:

Idea: Start from a node, find all the points that can continue to go below. Keep looking until you find the exit.
Method: Create an empty queue and put the starting point into the queue. Not a space-time loop in the queue: once out of the queue. If the current position is the exit, the algorithm is terminated; otherwise, four adjacent blocks of the current square can be found and all of them enter the queue.

Code:

from collections import  deque

mg = [
    [1,1,1,1,1,1,1,1,1,1],
    [1,0,0,1,0,0,0,1,0,1],
    [1,0,0,1,0,0,0,1,0,1],
    [1,0,0,0,0,1,1,0,0,1],
    [1,0,1,1,1,0,0,0,0,1],
    [1,0,0,0,1,0,0,0,0,1],
    [1,0,1,0,0,0,1,0,0,1],
    [1,0,1,1,1,0,1,1,0,1],
    [1,1,0,0,0,0,0,1,0,1],
    [1,1,1,1,1,1,1,1,1,1]
]

dirs = [lambda x, y: (x + 1, y),
        lambda x, y: (x - 1, y),
        lambda x, y: (x, y - 1),
        lambda x, y: (x, y + 1)]

def print_p(path):
    curNode = path[-1]
    realpath = []
    print('The maze path is:')
    while curNode[2] != -1:
        realpath.append(curNode[0:2])
        curNode = path[curNode[2]]
    realpath.append(curNode[0:2])
    realpath.reverse()
    print(realpath)

def mgpath(x1, y1, x2, y2):
    queue = deque()
    path = []
    queue.append((x1, y1, -1))
    while len(queue) > 0:
        curNode = queue.popleft()
        path.append(curNode)
        if curNode[0] == x2 and curNode[1] == y2:
            #Reach the finish line
            print_p(path)
            return True
        for dir in dirs:
            nextNode = dir(curNode[0], curNode[1])
            if mg[nextNode[0]][nextNode[1]] == 0:  # Find the next box
                queue.append((*nextNode, len(path) - 1))
                mg[nextNode[0]][nextNode[1]] = -1  # Marked as past
    return False


mgpath(1,1,8,8)

 

Single linked list

Each element in the list is an object, and each object is called a node, which contains the data field key and the next pointer to the next node. Through the interconnection of each node, a linked list is finally concatenated in series.

Node definitions:

class Node(object):
    def __init__(self, item):
        self.item = item
        self.next = None

a = Node(10)
b = Node(20)
c = Node(30)
a.next = b
b.next =c

Head node:

Traversal list:

def traversal(head):
    curNode = head  # Temporary pointer      
    while curNode is not None:
        print(curNode.item)
        curNode = curNode.next

You can only find the number from the front, but not from the front.

Insert:

p.next = curNode.next
curNode.next = p

Delete:

p = curNode.next
curNode.next = curNode.next.next
del p

Create linked list

Head insertion:

def createLinkListF(li):
    l = Node()
    for num in li:
        s = Node(num)
        s.next = l.next
        l.next = s
        return l

Tail insertion method:

def createLinkListR(li):
    l = Node()
    r = l       #r points to tail node    
    for num in li:
        s = Node(num)
        r.next = s
        r = s

 

 

Double linked list

Each node in the double linked list has two pointers: one pointing to the back node and one pointing to the front node.

Node definitions:

class Node(object):
    def __init__(self, item=None):
        self.item = item
        self.next = None
        self.prior = None

Head node:

 

Insert:

p.next = curNode.next
curNode.next.prior = p
p.prior = curNode
curNode.next = p

Delete:

p = curNode.next
curNode.next = p.next
p.next.prior = curNode
del p

Establishing Double Link List

Tail insertion method:

def createLinkListR(li):
    l = Node()
    r = l
    for num in li:
        s = Node(num)
        r.next = s
        s.prior = r
        r = s
        return l, r

 

 

Collections and Dictionaries in Python

Hash Table, also known as Hash Table, is a storage structure of linear tables. By using the keyword K of each object as an independent variable and through a hash function h(k), K is mapped to the subscript h(k), and the object is stored in this location.

For example: data set {1,6,7,9}, assuming that there exists a hash function h(x) such that h(1) = 0, h(6) = 2, h(7) = 4, h(9) = 5, the hash table is stored as [1,None, 6, None, 7, 9].

When we look for the location of element 6, we get the subscript (h(6) = 2) of the element through the hash function h(x), so we can find the element at 2 locations.

There are many kinds of hash functions, so we don't do further research here.

Hash conflict: Because the subscript range of hash table is limited and the value of element keyword is nearly infinite, it may occur that h(102) = 56, h(2003) = 56. At this point, two elements are mapped to the same subscript, resulting in hash conflicts.

Resolving the Hashi conflict:

  • Zipper method links all conflicting elements with linked list
  • Open Addressing Method Gets New Address by Hash Conflict Function

Dictionaries in Python:

A = {name':'Alex','age': 18,'gender':'Man'} uses a hash table to store the dictionary and maps the keys of the dictionary to subscripts through a hash function. Assuming that h('name') = 3, h('age') = 1, h('gender') = 4, the hash table is stored as [None, 18, None,'Alex','Man']

When the number of keys in a dictionary is small, there will be almost no hash collision, and the time complexity of finding an element is O(1).

Posted by benjaminbeazy on Sat, 20 Apr 2019 22:33:35 -0700