1 / 49

Algorytmy i struktury danych

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

lavina
Télécharger la présentation

Algorytmy i struktury danych

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Algorytmy i struktury danych struktury rekurencyjne tablice, listy, stosy, kolejki

  2. 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

  3. 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]

  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)

  5. 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 }

  6. 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

  7. 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

  8. 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[?];

  9. 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

  10. Lista jednostronnie wiązana data next data data next next data data next next cccccccc Root dddddddd AAAA bbbb xxxxxxxx

  11. 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

  12. 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)

  13. 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)

  14. 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)

  15. Lista jednostronnie wiązana- usuwanie elementu data next data data next next data data next next cccccccc Root dddddddd AAAA bbbb xxxxxxxx

  16. Lista jednostronnie wiązana- dodawanie elementu data next data data next next bbbb data data next next cccccccc Root dddddddd AAAA xxxxxxxx

  17. 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

  18. 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

  19. 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

  20. 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

  21. Lista dwustronnie wiązana CCCCCCCC prev data next Aaaa prev data next XXXXXXXX prev data next BBBBBBB prev data next Root bbbb

  22. 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)

  23. 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)

  24. Lista dwustronnie wiązanausuwanie elementu CCCCCCCC prev data next Aaaa prev data next XXXXXXXX prev data next BBBBBBB prev data next Root bbbb

  25. Lista dwustronnie wiązanawstawianie elementu CCCCCCCC prev data next Aaaa prev data next XXXXXXXX prev data next BBBBBBB prev data next Root bbbb

  26. 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

  27. 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)

  28. 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)

  29. 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) ??

  30. 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

  31. 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

  32. 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

  33. 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

  34. 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)

  35. 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)

  36. 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")

  37. 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)

  38. Lista cykliczna (jednostronna) Root Aaaa data next pWrite CCCCCCCC data next XXXXXXXX bbbb data next pRead BBBBBBB data next

  39. Lista cykliczna (dwustronna) Aaaa prev data next CCCCCCCC prev data next XXXXXXXX prev data next BBBBBBB prev data next Root pWrite bbbb pRead

  40. 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ć

  41. 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

  42. 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

  43. 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 * -

  44. 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

  45. 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

  46. ONP – przykład obliczeń

  47. 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

  48. 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

  49. ONP – przykład konwersji

More Related