Python object-oriented stack problem solving

Keywords: Python

Object oriented stack problem solving

What is object oriented

Object Oriented Programming (OOP) is simply to design and develop programs centered on objects, that is, to abstract the implemented software requirements into different objects and the interaction process between objects.

grammar

class Name(Object):
    pass
# Name: the name of the class (you can change it freely, but the beginning should be capitalized)
# Object: name of parent class (usually object)

Stack problem

It is known that there are n elements in the queue and the capacity of the stack is n-1. How many cases can the queue be output through the stack

analysis

Queue and stack

  • Queue: element first in first out
    • It can be compared with queuing
    • Those who come first can come first
  • Stack: Elements in and out
    • You can use the magazine analogy
    • The first bullet pressed in is the last one fired

How to solve this problem with object-oriented

  • First analyze what objects there are
    • A tool that can simulate the stacking and listing of elements
  • What can this object do
    • Can receive an element and perform column and stack operations
  • What properties does this object have
    • A queue and a stack

code

Defines the construction method of the class

class Simulator(object):

    def __init__(self):
        self.que = list()
        self.stk = list()
# This init method is called automatically when we create an object and does not need to be called manually

Define methods for stacking and listing
A function is called a method in a class. Its first parameter must be self, and then other parameters we need

  • eg:
class Name(object):

    def __init__(self):
        pass

    def func(self, var):
        pass

We need two parameters for the method of column and stack. One is self (there must be one), and the other is the element we want to column and stack. This method can be defined as follows

class Simulator(object):

    def __init__(self):
        self.que = list()
        self.stk = list()

    def inPut(self, seqv):
        pass

Let's continue to analyze:
After we receive an element, we can either stack or column it, but we can only go to one place first.
eg:
If our first element is 0, there are two cases
que: [0] | []
stk: [] | [0]
The second element is 1. There are four situations based on the first element
que: [0, 1] | [1] | [0] | []
stk: [] | [0] | [1] | [0, 1]
We can find that the first operation is to add a list composed of our incoming elements and an empty list. The subsequent operation is to add the original list and the list composed of our incoming elements. However, it should be noted that the list with the same index value of que and stk must have a corresponding relationship (all elements in the list with the same index value as stk must be the elements we have passed in before)
Here we can write the complete function

class Simulator(object):

    def __init__(self):
        self.que = list()
        self.stk = list()

    def inPut(self, seqv):
        if not(self.que or self.stk): # The first operation when both lists are empty
            self.que.append([seqv])
            self.stk.append([])
            self.que.append([])
            self.stk.append([seqv])
        else:
            n = len(self.que)
            for i in range(n):
                # Note: be sure to add [:]. After adding [:], a list will be generated and operated
                # Otherwise, python will directly reference the source address, which will cause an error
                self.que.append(self.que[i][:])
                self.stk.append(self.stk[i][:] + [seqv])
                self.que[i] += [seqv]

Define the method of stack in, stack out and column in
The elements we have put on the stack can also be put out of the stack into the column, which becomes a new situation
Then there are:

def out(self):
    n = len(self.que)
    for i in range(n):
        q, s = self.que[i][:], self.stk[i][:]
        q.append(s.pop()) # Out of stack and in column
        self.que.append(q[:])
        self.stk.append(s[:])

But the question is, can you only stack one element at a time?
Depending on the following:
que: []
stk:[1, 2, 3]
Then there
que: [3] | [3, 2] | [3, 2, 1]
stk:[1, 2] | [1] | []
There are three cases
So we don't know how many times to execute (because we don't know how many elements are in the stack), but we know when to end (we can stop when there are no elements in the stack)
So we can add a while loop with the condition len (s) > 0

def out(self):
    n = len(self.que)
    for i in range(n):
        q, s = self.que[i][:], self.stk[i][:]
        while len(s) > 0:
            q.append(s.pop())
            self.que.append(q[:])
            self.stk.append(s[:])

But there is another problem. When some elements are released, they will be repeated
such as
que: [] | [0]
stk: [0] | []
After the above operation, it will become
que: [] | [0] | [0]
stk: [0] | [] | []
Obviously, the third case repeats the first
So our code can be changed to remove duplication

def out(self):
    n = len(self.que)
    for i in range(n):
        q, s = self.que[i][:], self.stk[i][:]
        while len(s) > 0:
            q.append(s.pop())
            if q not in self.que:
                self.que.append(q[:])
                self.stk.append(s[:])

Or this:

def out(self):
    n = len(self.que)
    for i in range(n):
        q, s = self.que[i][:], self.stk[i][:]
        while len(s) > 0:
            q.append(s.pop())
            self.que.append(q[:])
            self.stk.append(s[:])
    q, s, self.que, self.stk = self.que, self.stk, [], []
    for i in range(len(q)):
        if q[i] not in self.que:
            self.que.append(q[i])
            self.stk.append(s[i])

Output results
The result is the reverse order of the queue + stack (because the stack is first in and last out)

def outPut(self):
    res = list()
    for i in range(len(self.que)):
        res.append(self.que[i][:] + self.stk[i][::-1])
    return res

But the same problem will be repeated
eg:
que1: [1, 2]
stk1: [3, 4]
res1: [1, 2, 4, 3]
que2: [1, 2, 4]
stk2: [3]
res2: [1, 2, 4, 3]
Although these two cases are two, the result is the same. Just one
So our code can be changed to this

def outPut(self):
    res = list()
    for i in range(len(self.que)):
        lis = self.que[i][:] + self.stk[i][::-1]
        if lis not in res:
            res.append(lis)
    return res

So far, our class is finished. We just need to create an object and start the operation

sim = Simulator() # create object
seq = input().split(",") # Get what you want to arrange
seqv = [i for i in range(len(seq))] # Take out the subscript of the obtained content
for i in seqv:
    sim.inPut(i)
    sim.out()
res = sim.outPut() # Obtain results and output
for i in res:
    for k in i:
        print(seq[k], end="")
    print()
print("common{}individual".format(len(res)))


But we found that this order is chaotic. What should we do if we want more orderly output?
To solve this problem, we just need to write a sorting function (or use the built-in sorting function in python)

def sort(lis):
    for i in range(len(lis) - 1):
        for j in range(len(lis) - i - 1):
            if lis[j] > lis[j + 1]:
                lis[j], lis[j + 1] = lis[j + 1], lis[j]
    return lis

Then add it to our code

res = sort(sim.outPut())

Source code reference

class Simulator(object):

    def __init__(self):
        self.que = list()
        self.stk = list()

    def inPut(self, seqv):
        if not(self.que or self.stk):
            self.que.append([seqv])
            self.stk.append([])
            self.que.append([])
            self.stk.append([seqv])
        else:
            n = len(self.que)
            for i in range(n):
                self.que.append(self.que[i][:])
                self.stk.append(self.stk[i][:] + [seqv])
                self.que[i] += [seqv]

    def out(self):
        n = len(self.que)
        for i in range(n):
            q, s = self.que[i][:], self.stk[i][:]
            while len(s) > 0:
                q.append(s.pop())
                self.que.append(q[:])
                self.stk.append(s[:])
        q, s, self.que, self.stk = self.que, self.stk, [], []
        for i in range(len(q)):
            if q[i] not in self.que:
                self.que.append(q[i])
                self.stk.append(s[i])

    def outPut(self):
        res = list()
        for i in range(len(self.que)):
            lis = self.que[i][:] + self.stk[i][::-1]
            if lis not in res:
                res.append(lis)
        return res


def sort(lis):
    for i in range(len(lis) - 1):
        for j in range(len(lis) - i - 1):
            if lis[j] > lis[j + 1]:
                lis[j], lis[j + 1] = lis[j + 1], lis[j]
    return lis


if __name__ == '__main__':
    sim = Simulator()
    seq = input().split(",")
    seqv = [i for i in range(len(seq))]
    for i in seqv:
        sim.inPut(i)
        sim.out()
    res = sort(sim.outPut())
    for i in res:
        for k in i:
            print(seq[k], end="")
        print()
    print("common{}individual".format(len(res)))

Operation results:

References for this article

  • Quick start to Python 3.7 programming (by Pan Zhongqiang and Xue Ying)
    • Chapter 5 classes and objects

Posted by Valdoua on Wed, 06 Oct 2021 20:27:23 -0700