Create a linked list function without creating another class - python

I am working on some practice exercises with linked lists and I got stuck with one function.
My program should create a Node class, take user input with create() function (number n and then takes in n number of elements), and has a function printLinkedList(p) to print it out. So far this works well but then I should create another function where I am going to be deleting the max element (if it occurs more than once, delete the first occurrence).
I found a function findMaxElement(p) that looks for the max, however, it doesn't work along my code (for example I get AttributeError: 'Node' object has no attribute 'head' error)
class Node:
def __init__(self, x = None):
self.data = x
self.next = None
def create():
n = int(input())
if n == 0:
return None
s = input().split()
p = Node(int(s[0]))
k = p
for i in range(1, n):
t = Node(int(s[i]))
k.next = t
k = t
return p
def printLinkedList(p):
if p == None:
print('Empty')
return
s = p
while s != None:
print(s.data, end = " ")
s = s.next
print()
def findMaxElement(p):
current = p.head
#Initializing max to initial node info
maximum = p.head.data
if(p.head == None):
print("List is empty")
else:
while(True):
#If current node's info is greater than max
#Then replace value of max with current node's info
if(maximum < current.info):
maximum = current.info
current= current.next
if(current == p.head):
break
return "Maximum value node in the list: "+ str(maximum)
#Driver code
a = create()
printLinkedList(a)
Input:
6
1 7 4 2 6 7
Expected result:
1 7 4 2 6 7
1 4 2 6 7

You could just define a findMaxElement() that traverses the linked-list in the same way that the printLinkedList() function is doing it (and finds the maximum value while doing so):
def findMaxElement(p):
if p == None:
return 'Empty List!'
current = p
maximum = p.data
while current != None: # Not end of list.
if current.data > maximum:
maximum = current.data
current = current.next
return "Maximum value node in the list: " + str(maximum)

Related

There is 8 puzzle game using a* algo. i want to set traversal limit of 2000 traversal in python

this is sample code of 8 puzzle game which take two matrix initial and goal state .
class Node:
def __init__(self,data,level,fval):
""" Initialize the node with the data, level of the node and the calculated fvalue """
self.data = data
self.level = level
self.fval = fval
def generate_child(self):
""" Generate child nodes from the given node by moving the blank space
either in the four directions {up,down,left,right} """
x,y = self.find(self.data,'_')
""" val_list contains position values for moving the blank space in either of
the 4 directions [up,down,left,right] respectively. """
val_list = [[x,y-1],[x,y+1],[x-1,y],[x+1,y]]
children = []
for i in val_list:
child = self.shuffle(self.data,x,y,i[0],i[1])
if child is not None:
child_node = Node(child,self.level+1,0)
children.append(child_node)
return children
def shuffle(self,puz,x1,y1,x2,y2):
""" Move the blank space in the given direction and if the position value are out
of limits the return None """
if x2 >= 0 and x2 < len(self.data) and y2 >= 0 and y2 < len(self.data):
temp_puz = []
temp_puz = self.copy(puz)
temp = temp_puz[x2][y2]
temp_puz[x2][y2] = temp_puz[x1][y1]
temp_puz[x1][y1] = temp
return temp_puz
else:
return None
def copy(self,root):
""" Copy function to create a similar matrix of the given node"""
temp = []
for i in root:
t = []
for j in i:
t.append(j)
temp.append(t)
return temp
def find(self,puz,x):
""" Specifically used to find the position of the blank space """
for i in range(0,len(self.data)):
for j in range(0,len(self.data)):
if puz[i][j] == x:
return i,j
class Puzzle:
def __init__(self,size):
""" Initialize the puzzle size by the specified size,open and closed lists to empty """
self.n = size
self.open = []
self.closed = []
def accept(self):
""" Accepts the puzzle from the user """
puz = []
for i in range(0,self.n):
temp = input().split(" ")
puz.append(temp)
return puz
def f(self,start,goal):
""" Heuristic Function to calculate hueristic value f(x) = h(x) + g(x) """
return self.h(start.data,goal)+start.level
def h(self,start,goal):
""" Calculates the different between the given puzzles """
temp = 0
for i in range(0,self.n):
for j in range(0,self.n):
if start[i][j] != goal[i][j] and start[i][j] != '_':
temp += 1
return temp
def process(self):
""" Accept Start and Goal Puzzle state"""
print("Enter the start state matrix \n")
start = self.accept()
print("Enter the goal state matrix \n")
goal = self.accept()
start = Node(start,0,0)
start.fval = self.f(start,goal)
""" Put the start node in the open list"""
self.open.append(start)
print("\n")
count=0
while True:
cur = self.open[0]
count=count+1
print("This Node number = \n", count)
print("")
print(" | ")
print(" | ")
print(" \\\'/ \n")
for i in cur.data:
for j in i:
print(j,end=" ")
print("")
""" If the difference between current and goal node is 0 we have reached the goal node"""
if(self.h(cur.data,goal) == 0):
break
for i in cur.generate_child():
i.fval = self.f(i,goal)
self.open.append(i)
self.closed.append(cur)
del self.open[0]
""" sort the opne list based on f value """
self.open.sort(key = lambda x:x.fval,reverse=False)
puz = Puzzle(3)
puz.process()
this code take initial state and goal state and start traversal and stop until
specific or reached goal state
i want to add limit of traversal to this code.so it itterate in
specific boundary either reached goal state or not

How do I create a Set method for a class with a variable-dimension container?

If I have a list class that can be initialized with a variable number of dimensions, how do I set an entry at the lowest level of the list with an element? (Also would like to know if my get method should work in theory)
I'm trying to simulate board games that use multiple dimensions (Can you even imagine 5-th dimensional chess? How about 17th?)
class Board():
DIMENSIONS = [8, 8]
#board and pieces have their respective rules.
def __init__(self, D=[8,8]):
if len(D) <= 0:
board = [None for i in range(D)]
else:
board = [None for i in range(D[0])]
for j in range(1,len(D)):
board = [board for i in range(D[j])]
def get(self, location):
try:
for coordinate in location:
result = board[coordinate]
return result
except:
print('Error: Cannot get coordinate')
return None
def set(self, location, piece):
try:
for coordinate in location:
result = self.board[coordinate]
result = piece
except:
print('Error: Cannot set coordinate')
def move(self, start, end):
x = self.get(start)
if x is not None:
for m, r in x.moves, x.rules:
if self.get(is_legitimate(self, start, m, r)) == end:
= x
pass
#Check alignment and position, if it's transformable react according to board rules.
#returns false if not, but returns location if legit.
def is_legitimate(self, start, move, rule):
location = start
forwardback = True
while move != 1:
primes = [2]
while move % primes[-1] == 0:
if forwardback:
location[len(primes) // 2]+=1
else:
location[len(primes) // 2]-=1
move = move % primes[-1]
if not self.bounds(location):
return False
primes.append(next_prime(primes))
forwardback = not forwardback
def bounds(self, location):
for coordinate, d in location, self.DIMENSIONS:
if coordinate < 0 or coordinate > d:
return False
return True
#using prime numbers?
def next_prime(primes):
if len(primes) == 0:
return 2
prev_result = 1
result = 2
while prev_result != result:
prev_result = result
for x in primes:
if result == x or result % x == 0:
result += 1
break
return result
Code is mostly rough draft, don't play just look.

Python: pop() returning py list, not my object

I'm trying to code an exercise to solve the Queen Puzzle (yes, typical, I know) on Python. I've made a class called Queens for board state that takes in the length of each side and the list of queens, if any.
In the main program, I have a list of Queens called frontier, which is then popped one by one. However, the result I get from popping seems to be of type list, and not Queens as expected!
What is causing this, and how do I fix it?
Code snippet:
from queens import Queens
def search(n, debug=False, max=6):
frontier = [Queens(n, [])] # queue of states to explore
while frontier != []:
check = frontier.pop()
print(type(check))
if debug:
print(str(numSolutions) + " | Checking:")
print(check)
v = check.validate()
# EDIT: added more of the code; problem seems to arise here
if v == 0:
if debug:
print("Solution!")
numSolutions += 1
if n <= max:
solutions.append(check)
elif v > 0:
if debug:
print(str(v) + " more")
frontier.append(check.branch())
else:
if debug:
print("Invalid state")
pass
expected output:
<class 'queens.Queens'>
actual output:
<class 'queens.Queens'>
<class 'list'>
(yes, the one type statement printed 2 lines)
EDIT: Since there seems to be no problem with the main code, here's the file in which I defined the class:
import array
import copy
class Queens:
__slots__ = ["n", "qlist"]
def __init__(self, n, qa=None):
self.n = n # store for print function
if qa == None:
self.qlist = array.array("h")
elif type(qa) == list:
self.qlist = array.array("h", qa)
else:
assert type(qa) == array.array
self.qlist = qa # list of positions for each line
def __str__(self):
out = ""
for q in range(self.n):
if q == 0:
out += "|"
else:
out += "\n|"
for space in range(self.n):
if q < len(self.qlist) and space == self.qlist[q]:
out += "Q|"
else:
out += " |"
return out
def branch(self):
out = []
for x in range(self.n):
if x not in self.qlist:
qlist = copy.deepcopy(self.qlist)
qlist.append(x)
out.append(Queens(self.n, qlist))
return out
def validate(self):
for y in range(len(self.qlist)):
# don't need to check horizontal;
# data structure doesn't let you place them
# don't need to check vertical;
# branching eliminates those
# check diagonals
for y2 in range(len(self.qlist)):
if y != y2:
expected = self.qlist[y] - y + y2
if 0 <= expected < self.n and self.qlist[y2] == expected:
return -1
expected = self.qlist[y] + y - y2
if 0 <= expected < self.n and self.qlist[y2] == expected:
return -1
return self.n - len(self.qlist)
if __name__ == "__main__":
q = Queens(4)
print(q.validate())
q = Queens(4, [0, 1, 2])
print(q.validate())
I've figured it out. The problem happened only after frontier.append(check.branch()). branch() returns a list of queens. I thought I was appending several queens to frontier, but I was, in fact, appending a list of queens to frontier. Changing append to extend solved the issue.
When you append to your frontier the result of .branch(..) and you re-iterate you get an array back (list). Which is being printed after the loop continues to the next step.
def branch(self):
out = []
for x in range(self.n):
if x not in self.qlist:
qlist = copy.deepcopy(self.qlist)
qlist.append(x)
out.append(Queens(self.n, qlist))
return out

how to fix the count function

class TN:
def __init__(self,value,left=None,right=None):
self.value = value
self.left = left
self.right = right
def list_to_tree(alist):
if alist == None:
return None
else:
return TN(alist[0],list_to_tree(alist[1]),list_to_tree(alist[2]))
def str_tree(atree,indent_char ='.',indent_delta=2):
def str_tree_1(indent,atree):
if atree == None:
return ''
else:
answer = ''
answer += str_tree_1(indent+indent_delta,atree.right)
answer += indent*indent_char+str(atree.value)+'\n'
answer += str_tree_1(indent+indent_delta,atree.left)
return answer
return str_tree_1(0,atree)
def count(t,value):
nodes = []
num = 0
nodes.append(t)
while len(nodes) > 0:
if nodes[0] == value:
num += 1
next = nodes.pop(0)
count(next,value)
return num
I need to write a recursive function count (other three functions cannot be changed); it is passed balanced binary tree and a value as arguments. It returns the number of times the values is in the tree. In the binary tree below, count(tree,1) returns 1, count(tree,2) returns 2, count(tree,3) returns 4
..1
....3
3
....3
..2
......2
....3
I called the following functions
tree = list_to_tree([3, [2, None, [3, None, None]], [1, [3, None, None], None]])
print('\nfor tree = \n',str_tree(tree))
for i in irange(1,3):
print('count(tree,'+str(i)+') = ', count(tree,i))
but it shows the error that "RecursionError: maximum recursion depth exceeded in comparison"
can someone help me to fix the count function? Thanks in advance.
If you look carefully at your code you'll see that you set up an empty nodes list, fill it with t, so the while loop is always entered you'll always pop t into next and always call the function with precisely the same parameters. That is of course an infinite recursion.
Here is one simple way of setting it up correctly:
def count(tree, number):
if tree is None:
return 0
else:
return (number == tree.value) + count(tree.left, number) \
+ count(tree.right, number)
Another way to go about it is using transversal, in a typical tree there is a root and a node subclass. Your tree is missing that structure so it looks a bit weird. To use transversal I'm using a global var to keep track of the counter.
class TN:
def __init__(self,value,left=None,right=None):
self.value = value
self.left = left
self.right = right
def list_to_tree(alist):
if alist == None:
return None
else:
return TN(alist[0],list_to_tree(alist[1]),list_to_tree(alist[2]))
def str_tree(atree,indent_char ='.',indent_delta=2):
def str_tree_1(indent,atree):
if atree == None:
return ''
else:
answer = ''
answer += str_tree_1(indent+indent_delta,atree.right)
answer += indent*indent_char+str(atree.value)+'\n'
answer += str_tree_1(indent+indent_delta,atree.left)
return answer
return str_tree_1(0,atree)
NUM = 0
def count(t,value):
global NUM
NUM = 0
if t != None:
if t.left == None and t.right == None:
if t.value == value:
return 1
else:
return 0
else:
_count(t, value)
return NUM
def _count(t, value):
if t.left != None:
_count(t.left, value)
if t.value == value:
global NUM
NUM += 1
if t.right != None:
_count(t.right, value)
tree = list_to_tree([3, [2, None, [3, None, None]], [1, [3, None, None], None]])
print(str_tree(tree))
print("count 1", count(tree, 1))
print("count 2", count(tree, 2))
print("count 3", count(tree, 3))

Python 8 puzzle BFS infinite loop

I am trying to solve the 8 puzzle problem using BFS search, however, my code seems to get stuck in an infinite loop where it only moves the zero tile back and forth until the memory of the queue ends the program in an error.
import collections
import queue
class Node:
def __init__(self, puzzle, last=None):
self.puzzle = puzzle
self.last = last
#property
def seq(self): # to keep track of the sequence used to get to the goal
node, seq = self, []
while node:
seq.append(node)
node = node.last
yield from reversed(seq)
#property
def state(self):
return str(self) # hashable so it can be compared in sets
#property
def isSolved(self):
return self.puzzle.isSolved
#property
def getMoves(self):
return self.puzzle.getMoves
class Puzzle:
def __init__(self, startBoard):
self.board = startBoard
#property
def getMoves(self):
possibleNewBoards = []
zeroPos = self.board.index(0) # find the zero tile to determine possible moves
if zeroPos == 0:
possibleNewBoards.append(self.move(0,1))
possibleNewBoards.append(self.move(0,3))
elif zeroPos == 1:
possibleNewBoards.append(self.move(1,0))
possibleNewBoards.append(self.move(1,2))
possibleNewBoards.append(self.move(1,4))
elif zeroPos == 2:
possibleNewBoards.append(self.move(2,1))
possibleNewBoards.append(self.move(2,5))
elif zeroPos == 3:
possibleNewBoards.append(self.move(3,0))
possibleNewBoards.append(self.move(3,4))
possibleNewBoards.append(self.move(3,6))
elif zeroPos == 4:
possibleNewBoards.append(self.move(4,1))
possibleNewBoards.append(self.move(4,3))
possibleNewBoards.append(self.move(4,5))
possibleNewBoards.append(self.move(4,7))
elif zeroPos == 5:
possibleNewBoards.append(self.move(5,2))
possibleNewBoards.append(self.move(5,4))
possibleNewBoards.append(self.move(5,8))
elif zeroPos == 6:
possibleNewBoards.append(self.move(6,3))
possibleNewBoards.append(self.move(6,7))
elif zeroPos == 7:
possibleNewBoards.append(self.move(7,4))
possibleNewBoards.append(self.move(7,6))
possibleNewBoards.append(self.move(7,8))
else:
possibleNewBoards.append(self.move(8,5))
possibleNewBoards.append(self.move(8,7))
return possibleNewBoards # returns Puzzle objects (maximum of 4 at a time)
def move(self, current, to):
changeBoard = self.board[:] # create a copy
changeBoard[to], changeBoard[current] = changeBoard[current], changeBoard[to] # switch the tiles at the passed positions
return Puzzle(changeBoard) # return a new Puzzle object
def printPuzzle(self): # prints board in 8 puzzle style
copyBoard = self.board[:]
for i in range(9):
if i == 2 or i == 5:
print((str)(copyBoard[i]))
else:
print((str)(copyBoard[i])+" ", end="")
print('\n')
#property
def isSolved(self):
return self.board == [0,1,2,3,4,5,6,7,8] # goal board
class Solver:
def __init__(self, Puzzle):
self.puzzle = Puzzle
def solveBFS(self):
startNode = Node(self.puzzle)
myQueue = collections.deque([startNode])
visited = set()
visited.add(myQueue[0].state)
while myQueue:
currentNode = myQueue.pop()
# currentNode.puzzle.printPuzzle() # used for testing
if currentNode.puzzle.isSolved:
return currentNode.seq
for board in currentNode.getMoves:
nextNode = Node(board, currentNode)
if nextNode.state not in visited:
myQueue.appendleft(nextNode)
visited.add(nextNode.state)
startingBoard = [7,2,4,5,0,6,8,3,1]
myPuzzle = Puzzle(startingBoard)
mySolver = Solver(myPuzzle)
goalSeq = mySolver.solveBFS()
counter = -1 # starting state doesn't count as a move
for node in goalSeq:
counter = counter + 1
node.puzzle.printPuzzle()
print("Total number of moves: " + counter)
I thought adding each node to a set() would stop the code from getting caught in a loop. Is this not true?
#property
def state(self):
return str(self) # hashable so it can be compared in sets
This will return something that looks like <__main__.Node object at 0x02173A90>. The address is unique per Node object, so the state of two nodes with identical boards will still be considered distinct by the set.
Instead, try:
#property
def state(self):
return str(self.puzzle.board)
Now two Nodes with identical boards will be considered the same.
Also, change the last line of your script to
print("Total number of moves: " + str(counter))
Now you will get a result:
7 2 4
5 0 6
8 3 1
7 2 4
0 5 6
8 3 1
(snip)
1 0 2
3 4 5
6 7 8
0 1 2
3 4 5
6 7 8
Total number of moves: 26

Categories