510 likes | 530 Views
Algorithms and data structures. Recursive structures array , list, stack , queue. Array – random access structure. C/C++ const int MAX = 12; int Data [MAX] = {1,7,2,4,8,11,7,2}; Pseudokod Data = [1,7,2,4,8,11,7,2,0,0,0,0] # in fact in Python this is called list Data [ 5 ] = 5
E N D
Algorithmsand data structures Recursive structures array, list, stack, queue
Array – random access structure C/C++ const int MAX = 12; int Data[MAX] = {1,7,2,4,8,11,7,2}; Pseudokod Data = [1,7,2,4,8,11,7,2,0,0,0,0] # in fact in Python this is called list Data[5] = 5 int i = 1 Data[i] = 5 Data[i+2] = 5 1 7 5 2 4 8 5 11 7 2 5
Pseudocode again • Range in Python is a list and is indexed from 0 • Time of access is like for a list (i.e. o(n)) • Checking of lenght could be done with len function • Iterating for element in A : ..... • For defining ranges could be used range function range(1,10)returns range 1,2,3,4,5,6,7,8,9range(1,9,4) returns range 1, 5range(5,3) returns empty range range(5,3,-1) returns range 5, 4 So, the given codes are working in Python but given complexities are not valid because in Python [] denotes list
Pseudocode again • Altough changes applied to parameters in Python are not transfered outside we will avoid sich constructions in pseudocode. • There is not necessary to free memory in Python and we will ommit this in pseudocode.
Array – basic operations • Random access structure Operations • Writing - (1) : • A[i] = newValue • Reading - (1) : • value =A[i] • if value == A[i] • Searching through - O(n) or O(log n)depend on existence of elements order • for e in A : ... • for i in range(0,len(a)) : if A[i] == s : ... • element = find(A,pattern)
Array – additional operations • Inserting - O(n) – n = number of moved elements for i in range(n-1, k, -1) : A[i+1] = A[i] A[k] = newElement • Changing the size - (n) : C/C++ : Resize(A, newSize) { tmp = alloc_the_new_array Copy_elements_from_A_to_the_temp free_A return tmp }
Array of pointers xxx yyy zzz aaa bbb ccc ddd eee C/C++ ELEMENT Array[MAX]; ELEMENT *Array[MAX]; xxx yyy zzz aaa bbb NULL ccc NULL NULL ddd NULL eee In Python, .Net, Java objects (i.e. class instances) have pointer nature
Swaping elements xxx xxx yyy yyy yyy zzz zzz zzz aaa bbb ccc aaa ddd eee bbb NULL ccc NULL NULL ddd NULL eee
Warning Pointers have to point to something. We can allocate elements one by one or use an additional memory block/array xxx ELEMENT Array[...]; C/C++ :Element *Array[MAX]; for (i.... ) A[i] = new Element; yyy zzz aaa for (....)Array[i] = &tab[j]; bbb ccc NULL ddd NULL eee NULL NULL ELEMENT tab[?]; !! Not used cells have to be NULL-ed
Recurson of data C/C++ typedef int DATA; typedef struct SLNODE { DATA data; SLNODE *next; } *PSLNODE; SLNODE OneElement; C/C++ - another way typedefint DATA; structSLNODE; typedefSLNODE * PSLNODE; struct NODE { DATA data; PSLNODE next; } OneElement; Pseudokod : class SLNODE : data = None next = None
Singly linked list data next data data next next data data next next cccccccc Root dddddddd AAAA bbbb xxxxxxxx
Singly linked list class NODE : data = None next = None def PrintList(firstNode) :tmp = firstNodewhile tmp != None :print(tmp.data)tmp = tmp.next def GetListLen(firstNode) : cnt = 0tmp = firstNodewhile tmp != None : cnt = cnt+1 tmp = tmp.nextreturn cnt
Singly linked list def GetFirst(firstNode) : if firstNode ==None :return None return firstNode def GetLast(firstNode) : if firstNode ==None :return None tmp = firstNode while tmp.next!=None : tmp = tmp.next return tmp Ussage : lastNode = GetLast(list)
Singly linked list def AddFirst(firstNode, newNode) : newNode.next = firstNodereturn newNode def AddLast(firstNode, newNode) : newNode.next = None if firstNode == None :return newNode tmp = firstNodewhile tmp.next != None :tmp = tmp.nexttmp.next = newNodereturn firstNode Użycie : list = NonenewNode = Node()newNode.data = "abc" list = AddLast(list,newNode)
Singly linked list def RemoveFirst(firstNode) :if firstNode == None : return Nonereturn firstNode.next def RemoveLast(firstNode) :if firstNode ==None :return None if firstNode.next==None : return None tmp = firstNodewhile tmp.next.next!=None : tmp = tmp.nexttmp.next = Nonereturn firstNode Ussage : list = RemoveFirst(list)
Singly linked list – element removing data next data data next next data data next next cccccccc Root dddddddd AAAA bbbb xxxxxxxx
Singly linked list – element inserting data next data data next next bbbb data data next next cccccccc Root dddddddd AAAA xxxxxxxx
Singly linked list def FindNode(firstNode,dataPattern) : tmp = firstNodewhile tmp != None :if tmp.data == dataPattern : return tmp tmp = tmp.nextreturn None def GetAtPos(firstNode,pos) :#function returns element at position pos (0-based)#or None if not existstmp = firstNodewhile tmp != None : if pos == 0 : return tmp pos = pos – 1 tmp = tmp.nextreturn None
Singly linked list def InsertAfter(newNode, node) : if node!= None : newNode.next = node.nextnode.next = newNode def RemoveAfter(node) : if node!= None : node.next = node.next.next #We skipped memory dealocation! #InsertBefore and RemoveNode – require #modification of previous node #So we have to find the previous node
Singly linked list def InsertBefore(firstNode,newNode,dataPattern) : if firstNode ==None : return firstNodeif firstNode.data ==dataPattern :newNode.next = firstNode return newNodetmp = firstNodewhile tmp.next != None : if tmp.next.data == dataPattern : newNode.next = tmp.next tmp.next = newNode break tmp = tmp.next return firstNode
Singly linked list def RemoveNode(firstNode,dataPattern) : if firstNode == None : return firstNodeif firstNode.data ==dataPattern :return firstNode.next tmp = firstNode while tmp.next != None : if tmp.next.data == dataPattern : tmp.next = tmp.next.next break tmp = tmp.next return firstNode
Doubly linked list CCCCCCCC prev data next Aaaa prev data next XXXXXXXX prev data next BBBBBBB prev data next Root bbbb
Doubly linked list class DLNODE :data = Nonenext = None prev = None We can use previous functions : PrintList(list) GetListLen(list) GetFirst(list) GetLast(list) GetAtPos(list, pos)
Doubly linked list def AddFirst(firstNode, newNode) :newNode.prev = NonenewNode.next = firstNodeif firstNode != None : firstNode.prev = newNode return newNode def AddLast(firstNode, newNode) :last = GetLast(firstNode)newNode.prev = lastif last == None : return newNode last.next = newNode return firstNode Ussage : newNode = DLNODE() newNode.data = "ABC" list = AddLast(list,newNode)
Doubly linked list -element removing CCCCCCCC prev data next Aaaa prev data next XXXXXXXX prev data next BBBBBBB prev data next Root bbbb
Doubly linked list – element inserting CCCCCCCC prev data next Aaaa prev data next XXXXXXXX prev data next BBBBBBB prev data next Root bbbb
Doubly linked list def InsertAfter(newNode, node) :if node==None : return newNode.next = node.nextnewNode.prev = nodeif node.next!=None :node.next.prev = newNode node.next = newNode def RemoveAfter(node) :if node==None : returnif node.next ==None : returnnode.next = node.next.next if node.next!=None :node.next.prev = node
Doubly linked list def InsertBefore (firstNode, newNode, node) :if node==None : return firstNodenewNode.next = nodenewNode.prev = node.prevnode.prev = newNodeif newNode.prev==None : #very first node is added return newNode newNode.prev.next = newNodereturn firstNode Ussage : node = FindNode(list, whatToFind)list = InsertBefore(list, newNode, node)
Doubly linked list def RemoveNode(firstNode, node) :if node==None : return firstNodeif node.next!= None : node.next.prev = node.previf node.prev == None : #i.e. firstNode==node return node.nextnode.prev.next = node.nextreturn firstNode Użycie : node = FindNode(list, whatToFind)list = RemoveNode(list, node)
Doubly linked list def RemoveFirst(firstNode) : return RemoveNode(firstNode, firstNode) def RemoveLast(firstNode) :last = GetLast(firstNode) return RemoveNode(firstNode, last) Ussage : list = RemoveFirst(list)
List – sequential access structure Operations : • Searching through - O(n) • Inserting ath the beggining - (1) • Removing the first element - (1) • Inserting to i-th pos - O(i) : GetAt+InsertAfter • Read - O(n) : GetAt(list,i-1) • Inserting at the end (n) ?? • Removing the last element (n) ??
Stack - Last In First Out Example of application: DFS zzz zzz ttt Pop zzz ttt xxx Push yyy zzz aaa bbb ccc ddd eee
Queue - First In First Out zzz ttt eee Example of application: BFS Put zzz ttt xxx yyy zzz aaa bbb ccc ddd Get eee
Stack implemented with array aaa aaa bbb bbb bbb 1 2 1 cnt=0 def Push(element) : if cnt < MAXarray[cnt] = elementcnt= cnt+1else : ERROR("overflow") def Pop() if cnt <=0 :ERROR("stack is empty")else : cnt = cnt-1 return array[cnt] array[MAX]; 0 cnt Problem : limited capacity
Queue implemented with array aaa aaa aaa bbb bbb 1 2 1 1 ELEMENT array[MAX]; Problem : • limited capacity • migration of elements Implementation • Moving elements when end of buffer is reached • Tracing the begining and the end of elements (complex) – cyclic buffer 0 long Cnt 0 long First
Stack/queue implemented with list • Push -> AddFirst() => (1) • Put -> AddLast() => (n) or O(1) • Pop/Get -> GetFirst() + RemoveFirst() => (1) Push, Put alocate the new node (i.e. they got the data as a parameter) def Push(stack, dataToStore) : node = SLNODE() node.data = dataToStore return AddFirst(stack, node) def Put(queue, dataToStore) : node = DLNODE() node.data = dataToStore return AddLast(queue, node)
Stack/queue implemented with list Get, Pop return data (not node) (and deallocation was skipped) def Pop(stack) : ret = GetFirst(stack) if ret==None : ERROR("Stack is empty") return RemoveFirst(stack), ret.data def Get(queue) : ret = GetFirst(queue) if ret==None : ERROR("Queue is empty")return RemoveFirst(queue), ret.data Ussage: stack,value = Pop(stack)
Queue implemented with list O(1) def Put(firstNode, lastNode, dataToStore) :node = DLNODE()node.data = dataToStorenode.next = None node.prev = lastNodeif lastNode ==None :# queue is emptyreturn node, node lastNode.next = nodereturn firstNode, node Ussage : start,end = Put(start,end,"abc")
Queue implemented with list O(1) def Get(firstNode, lastNode) : if firstNode===None : ERROR("Kolejka jest pusta")elif firstNode == lastNode : return None, None, firstNode.dataif (firstNode.next == None) : return None, None, firstNode.data ret = firstNode.data return RemoveFirst(firstNode), lastNode, ret Ussage : start,end,value = Get(start,end)
Cyclic list (singly linked) Root Aaaa data next pWrite CCCCCCCC data next XXXXXXXX bbbb data next pRead BBBBBBB data next
Cyclic list (doubly linked) Aaaa prev data next CCCCCCCC prev data next XXXXXXXX prev data next BBBBBBB prev data next Root pWrite bbbb pRead
Cyclic list • The last element points to the first one • In case of doubly linked list – also the first element points to the last one • Insert, remove are similar to non-cyclic list • Searching: it is necessary to remember the begining to know when finish the search • Joning of two lists – what time?
Pointer structures – without pointers xxx yyy zzz aaa bbb ccc ddd eee int arrOfPtrs[MAXPTR]; ELEMENT elements[MAXEL]; 0 1 3 -1 -1 -1 -1 -1 int ptr; 3
Stack application - example • Locations visiting – DFS def VisitRooms(startRoom) :stack = []stack = Push(stack, startRoom)while stack != None :stack,current = Pop(stack)neighbours = get_neighbours(current) for room in neighbours : if not already_visited(room) :mark_visited(room) stack = Push (stack, room) • Locations visiting - BFS : Push -> PutPop -> Get
Reverse Polish Notation • Base on notation proposed by Jan Łukasiewicz • It allows to express and perform calculation without parenthesis, priorities etc. • a+b*c ONP: a b c * + • a+b*c-7 ONP: a b c * + 7 - • b*c-(d+e)*4 ONP: b c * d e + 4 * - ONP is ambigious i.e. single expression can be represented in more than one (legal) way
ONP - calculation Calculation : • Process all the ONP tokens • If token is operand push to the stack • If token is operator • Pull from the stack proper number of elements • Do calculations • Push the result to the stack • The top of stack is a Result
ONP - calculation def ONPCalc(onp) : ’’’Function returns the result of ONP expression evaluation. Example : 3 4 * 2 +’’’stack = None while onp != None :onp,token = get_next_token(onp) if is_operand(token) : stack = Push(stack, token) else : stack, op1 = Pop(stack) stack, op2 = Pop(stack) result = do_calculation(token,op1,op2) stack = Push(stack, result)stack,result = Pop(stack)return result
Conversion to ONP Conversion : Get next expression token If token is operand write token to output If token is operator "(" push it stack If token is operator ")" pull from stack all the operators until "(" including this one If token is other operator pull from stack all operators with higher or equal (not less important) priorities and write to outputpush token to stack When all the elements are processed write all stack (one by one) to output
ONP - conversion def ONPConv(expression) :stack = Noneonp = Nonewhile expression != None :expression, token = get_next_token(expression) if is_operand(token):onp = Put(onp, token) elif token == "(" : stack = Push(stack, token) elif token == ")" : while stack != None : stack,token = Pop(stack) if token =="(" : break else : onp = Put(onp,token) else :priority = get_priority(token) while stack != None :stack,top = Pop(stack) if top=="(" or get_priority(top)<priority : stack = Push(stack,top)break onp = Put(onp, top)stack = Push(stack,token) while stack != None : stack, item = Pop(stack) onp = Put(onp, item)return onp