500 likes | 786 Views
Algorytmy i struktury danych. s truktury rekurencyjne tablice, listy, stosy, kolejki. Tablica – struktura o swobodnym dostępie. C/C++ const int MAX = 12; int i, Data [MAX] = {1,7,2,4,8,11,7,2}; Pseudokod Data = [1,7,2,4,8,11,7,2,0,0,0,0] # de facto w Pythonie nazywa się to lista i = 1
E N D
Algorytmy i struktury danych struktury rekurencyjne tablice, listy, stosy, kolejki
Tablica – struktura o swobodnym dostępie C/C++ const int MAX = 12; int i, Data[MAX] = {1,7,2,4,8,11,7,2}; Pseudokod Data = [1,7,2,4,8,11,7,2,0,0,0,0] # de facto w Pythonie nazywa się to lista i = 1 Data[i] = 5 Data[5] = 5 Data[i+2] = 5 1 7 5 2 4 8 5 11 7 2 5
Jeszcze o pseudokodzie • tablica (lista w Pythonie) indeksowane są od 0 • sprawdzanie długości możliwe jest funkcją len • tablice można konkatenować t1 = t2+t3 • iterowanie for element in A : ..... • do definiowania zakresów służy funkcja range range(1,10)zwraca zakres 1,2,3,4,5,6,7,8,9range(1,9,4)zwraca zakres 1, 5range(5,3)zwraca zakres []range(5,3,-1)zwraca zakres [5, 4]
Tablica – podstawowe operacje • Struktura o dostępie swobodnym Operacje • Zapis - (1) : • A[i] = newValue • Odczyt - (1): • value =A[i] • if value == A[i] • Przeszukiwanie - O(n) lub O(log n)w zależności oduporządkowania • for e in A : ... • for i in range(0,len(a)): if A[i] == s: ... • element = find(A,pattern)
Tablica – dodatkowe operacje • Wstawianie - O(n) – n = liczba elementów przed for i in range(n-1, k, -1) : A[i+1] = A[i] A[k] = newElement • Zmiana rozmiaru - (n): C/C++: Resize(A, newSize) { tmp = alokuj_nowa_tablice kopiuj_elementy_z_A_do_nowej_tablicy zwolnij_A return tmp }
Tablica wskaźników 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 W jęz. Python, .Net, Java obiekty klas mają charakter wkaźników
Zamiana elementów xxx xxx yyy yyy yyy zzz zzz zzz aaa bbb ccc aaa ddd eee bbb NULL ccc NULL NULL ddd NULL eee !! Uwaga należy wyzerować nieużywane komórki
UWAGA Musimy mieć na co pokazywać, można alokować pojedyncze elementy lub skorzystać z dodatkowej tablicy 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[?];
Rekurencja danych C/C++ typedef int DATA; typedef struct SLNODE { DATA data; SLNODE *next; } *PSLNODE; SLNODE OneElement; C/C++ - inaczej typedef int DATA; struct SLNODE; typedef SLNODE * PSLNODE; struct NODE { DATA data; PSLNODE next; } OneElement; Pseudokod: class SLNODE : data = None next = None
Lista jednostronnie wiązana data next data data next next data data next next cccccccc Root dddddddd AAAA bbbb xxxxxxxx
Lista jednostronnie wiązana class NODE : data = None next = None def PrintList (list):tmp = listwhile tmp != None: print tmp.data tmp = tmp.next def ListLen(list): cnt = 0tmp = listwhile tmp != None : cnt = cnt+1 tmp = tmp.nextreturn cnt
Lista jednostronnie wiązana def AddHead(list, newNode): newNode.next = listreturn newNode def AddTail(list, newNode): newNode.next = None if list == None: return newNode else : tmp = list while tmp.next != None : tmp = tmp.nexttmp.next = newNode return list Użycie: newNode = Node()newNode.data = "abc" list = AddTail(list,newNode)
Lista jednostronnie wiązana def GetHead (list): if list==None : return None else : return list def GetTail(list): if list==None : return None else: tmp = list while tmp.next!=None: tmp = tmp.next return tmp Użycie: lastNode = GetEnd(list)
Lista jednostronnie wiązana def RemoveHead(list): if list== None : return Noneelse : return list.next def RemoveTail(list):if list==None : return None elif list.next==None : return None else: tmp = list while tmp.next.next!=None: tmp = tmp.next tmp.next = None return list Użycie: list = RemoveHead(list)
Lista jednostronnie wiązana- usuwanie elementu data next data data next next data data next next cccccccc Root dddddddd AAAA bbbb xxxxxxxx
Lista jednostronnie wiązana- dodawanie elementu data next data data next next bbbb data data next next cccccccc Root dddddddd AAAA xxxxxxxx
Lista jednostronnie wiązana def FindNode(list,dataPattern): tmp = listwhile tmp != None: if tmp.data == dataPattern : return tmpreturn None def GetAt(list,pos):#funkcja zwraca element na pozycji pos liczac od 0#jesli nie ma tylu elementow zwraca Nonetmp = listwhile tmp != None: if pos == 0 : return tmp pos = pos - 1return None
Lista jednostronnie wiązana def InsertAfter(node, newNode):newNode.next = node.nextnode.next = newNode def DeleteAfter(node):node.next = node.next.next #InsertBefore i DeleteNode – wymagaja #modyfikacji wezla wczesniejszego
Lista jednostronnie wiązana def InsertBeforeNode(list,newNode,dataPattern): if list==None : return listelif if list.data ==dataPattern: newNode.next = list return newNodeelif list.next==None :return listelse: tmp = list while tmp.next != None: if tmp.next.data == dataPattern : newNode = tmp.next tmp.next = newNode break return list
Lista jednostronnie wiązana def DeleteNode(list,dataPattern): if list== None : return listelif if list.data ==dataPattern: return list.next elif list.next== None :return listelse: tmp = list while tmp.next != None : if tmp.next.data == dataPattern : tmp.next = tmp.next.next break return list
Lista dwustronnie wiązana CCCCCCCC prev data next Aaaa prev data next XXXXXXXX prev data next BBBBBBB prev data next Root bbbb
Lista dwustronnie wiązana class DLNODE :data = Nonenext = None prev = None Identyczne będą funkcje: PrintList(list) ListLen(list) GetHead(list) GetTail(list) FindNode(list,dataPattern)
Lista dwustronnie wiązana def AddHead(list, newNode):newNode.prev = NonenewNode.next = listif list!= None: list.prev = newNode return newNode def AddTail(list, newNode): tail = GetTail(list)newNode.prev = tailif tail== None : return newNode tail.next = newNode return list Użycie: newNode = DLNODE() newNode.data = "ABC" list = AddTail(list,newNode)
Lista dwustronnie wiązanausuwanie elementu CCCCCCCC prev data next Aaaa prev data next XXXXXXXX prev data next BBBBBBB prev data next Root bbbb
Lista dwustronnie wiązanawstawianie elementu CCCCCCCC prev data next Aaaa prev data next XXXXXXXX prev data next BBBBBBB prev data next Root bbbb
Lista dwustronnie wiązana def InsertAfter(node, newNode):if node==None: return newNode.next = node.nextnewNode.prev = nodeif node.next!=None :node.next.prev = newNode node.next = newNode
Lista dwustronnie wiązana def InsertBefore (list, node, newNode):if node==None : return listnewNode.next = nodenewNode.prev = node.prevnode.prev = newNodeif newNode.prev==None : #i.e.node is the only one return newNode newNode.prev.next = newNodereturn list Użycie: node = FindNode(list, whatToFind)list = InsertBefore(list, node, newNode)
Lista dwustronnie wiązana def DeleteNode(list, node):tmp = node.next if node.next!= None : node.next.prev = node.previf node.prev == None : #i.e. list == node return node.nextnode.prev.next = node.nextreturn list Użycie: node = FindNode(list, whatToFind)list = DeleteNode(list, node)
Lista - struktura o dostępie sekwencyjnym Operacje: • Przeszukiwanie - O(n) (zależy ? od uporządkowania) • Wstawianie na poczatek - (1) • Usuwanie z poczatku - (1) • Zapis na i-ta pozycję - O(n) : GetAt+InsertAfter • Odczyt - O(n): GetAt(list,i-1) • Wstawianie na koniec (n) ?? • Usuwanie z końca (n) ??
Stos - Last In First Out Przykład zastosowania np. DFS zzz zzz ttt Pop zzz ttt xxx Push yyy zzz aaa bbb ccc ddd eee
Kolejka - First In First Out zzz ttt eee Przykład zastosowania np. BFS Put zzz ttt xxx yyy zzz aaa bbb ccc ddd Get eee
Tablicowa realizacja stosu aaa aaa bbb bbb bbb 1 2 1 Cnt=0 def Push(Element): if Cnt<MAXArray[Cnt] = Element Cnt=Cnt+1else: ERROR("przepelnienie") def Pop() if Cnt<=0:ERROR("stos pusty")else: cnt = cnt-1 return Array[cnt] } Array[MAX]; 0 Cnt Problem:Ograniczona pojemność stosu
Tablicowa realizacja kolejki aaa aaa aaa bbb bbb 1 2 1 1 ELEMENT Array[MAX]; Problem: • ograniczona pojemność stosu • wędrujące elementy Realizacja • realokacji elementów po osiągnięciu końca buforu • śledzenie początku i końca (skomplikowane) – tzw. bufor cykliczny 0 long Cnt 0 long First
Listowa realizacja stosu/kolejki • Push -> AddHead() => (1) • Put -> AddTail() => (n)lub O(1) • Pop/Get -> GetHead() + DeleteHead() => (1) Poniższy Push, Put same alokują nowy węzeł listy (tj. jako parametr otrzymują dane do umieszczenia na stosie/w kolejce) def Push(stack, data2Store): node = NODE() node.data = data2Store return AddHead(stack, node) def Put(queue, data2Store): node = NODE() node.data = data2Store return AddTail(queue, node)
Listowa realizacja kolejki/stosu Poniższe Get, Pop zwracają dane a nie węzły listy Z: węzeł nie wymaga dealokacji (w C/C++ trzeba dodać) def Pop(stack): ret = GetHead(stack) if ret==None: ERROR("Stos jest pusty") else: return (DeleteHead(stack), ret.data) def Get(queue): ret = GetHead(queue) if ret==None : ERROR(“Kolejka jest pusta") else: return (DeleteHead(stack), ret.data)Użycie: stack,value = Pop(stack)
Listowa realizacja kolejki w czasie stałym def Put(startList, endList, data2store):node = DLNODE()node.data = data2storenode.next = Nonenode.prev = endListif endList ==None :return (node, node) endList.next = nodereturn (startList, node) Użycie: start,end = Put(start,end,"abc")
Listowa realizacja kolejki w czasie stałym def Get(startList, endList): if startList==None : ERROR("Kolejka jest pusta")elif startList==endList: return (None, None, startList.data)else: ret = startList newStartList = startList.next newStartList.prev = None return (newStartList, endList, ret.data) Użycie: start,end,value = Get(start,end)
Lista cykliczna (jednostronna) Root Aaaa data next pWrite CCCCCCCC data next XXXXXXXX bbbb data next pRead BBBBBBB data next
Lista cykliczna (dwustronna) Aaaa prev data next CCCCCCCC prev data next XXXXXXXX prev data next BBBBBBB prev data next Root pWrite bbbb pRead
Lista cykliczna • Ostatni element pokazuje na pierwszy • W przypadku cyklicznej l. dwukierunkowej – również pierwszy na ostatni • Wstaw, usuń analogicznie do listy zwykłej • Szukanie – należy zapamiętać początek poszukiwań aby wiedzieć kiedy je zakończyć
Struktury wskaźnikowe bez wskaźników 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
Przykład użycia stosu • odwiedzanie pomieszczen – DFS def VisitRooms(start):stack = None stack = Push(stack, start)while (stack!= None) : stack,current = Pop(stack) neighbours = get_neighbourhood(current) for room in neighbours : if not already_visited(room): stack = Push (stack, room) • odwiedzanie pomieszczen BFS: Push -> PutPop -> Get
Odwrotna Notacja Polska • Rozwinięcie notacji zaproponowanej przez Jana Łukasiewicza • Pozwala wykonywać obliczenia bez nawiasów, bez potrzeby stosowania prorytetów • a+b*c przedstawiane jest jako a b c * + • a+b*c-7 przedstawiane jest jako a b c * + 7 - • b*c-(d+e)*4 przedstawiane jest jako b c * d e + 4 * -
ONP - obliczenia def ONPCalc(onp): "Funkcja oblicza wyniki wyrazenia w ONP Obslugiwane są operatory 2 argumentowe. Przyklad 3 4 * 2 +"stack = None while onp!= None : item = get_next_token(onp) if is_operand(item): stack = Push(stack,item) else: stack, op1 = Pop(stack) stack, op2 = Pop(stack) result = do_calculations(item, op1, op2) stack = Push(stack, result)stack,result = Pop(stack)return result
ONP - obliczenia Obliczenia: • weź element wyrażenia • jeżeli to operand połóż go na stosie • jezeli to operator zdejmij ze stosu odpowiednią liczbę operandów, wykonaj obliczenia i odłóż wynik na stos • wynik znajduje sie na górze stosu
ONP - konwersja Konwersja: • Pobierz kolejny element wyrazenia • Jesli jest to operand przepisz na wyjście • Jeśli jest to operator ")" zdejmij se stosu wszystkie operatory aż do nawiasu otwierającego • Jeśli jest to operator "(" połóż go na stosie • Jeśli to inny niż nawiasy zdejmij se stosu wszystkie operatory o priorytecie wyższym lub równym do bieżącego i połóż bieżacy operator na stosie • Po przetworzeniu wyrażenia przepisz stos na wyjście
ONP - konwersja def ONPConv(expression):stack = None onp = None while expression!= None : item = get_next_token(expression) if is_operand(item) : onp = onp + [item] elif item == "(" : stack = Push(stack,item) elif item == ")" : while (stack!= None): stack,item = Pop(stack) if item=="(": break else : onp = onp + [item] else:priority = get_priority(item) while (stack!= None): top = GetHead(stack).data if top=="(": break if get_priority(top)<priority: breakonp = onp + [top] stack = RemoveHead(stack) stack = Push(stack,item) while stack!= None : stack, item = Pop(stack) onp = onp + [item]return onp