Jak napisać listę jednokierunkową?

Podobne dokumenty
Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

Wskaźnik może wskazywać na jakąś zmienną, strukturę, tablicę a nawet funkcję. Oto podstawowe operatory niezbędne do operowania wskaźnikami:

Deklaracja struktury w C++

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Podstawy języka C++ Maciej Trzebiński. Instytut Fizyki Jądrowej Polskiej Akademii Nauk. Praktyki studenckie na LHC IVedycja,2016r.

Czym są właściwości. Poprawne projektowanie klas

Algorytmy i złożoności. Wykład 3. Listy jednokierunkowe

Listy powiązane zorientowane obiektowo

Podstawy języka C++ Maciej Trzebiński. Praktyki studenckie na LHC IFJ PAN. Instytut Fizyki Jądrowej Polskiej Akademii Nauk. M. Trzebiński C++ 1/16

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Programowanie Obiektowo Zorientowane w języku c++ Przestrzenie nazw

Programowanie - wykład 4

Dynamiczne struktury danych

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Programowanie komputerowe. Zajęcia 1

Część 4 życie programu

Zajęcia nr 2 Programowanie strukturalne. dr inż. Łukasz Graczykowski mgr inż. Leszek Kosarzewski Wydział Fizyki Politechniki Warszawskiej

I - Microsoft Visual Studio C++

Programowanie i struktury danych

1 Podstawy c++ w pigułce.

Pytania sprawdzające wiedzę z programowania C++

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Laboratorium 1 - Programowanie proceduralne i obiektowe

1 Podstawy c++ w pigułce.

Materiał uzupełniający do ćwiczen z przedmiotu: Programowanie w C ++ - ćwiczenia na wskaźnikach

Wstęp do programowania

Assembler w C++ Syntaksa AT&T oraz Intela

Czym jest całka? Całkowanie numeryczne

Ok. Rozbijmy to na czynniki pierwsze, pomijając fragmenty, które już znamy:

STL: Lekcja 1&2. Filozofia STL

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania

7. Pętle for. Przykłady

Podstawy programowania skrót z wykładów:

Podstawy Programowania 2 Dwukierunkowa lista liniowa. Plan. Wstęp. Implementacja. Notatki. Notatki. Notatki. Notatki.

Wskaźniki. nie są konieczne, ale dają językowi siłę i elastyczność są języki w których nie używa się wskaźników typ wskaźnikowy typ pochodny:

Paradygmaty programowania. Paradygmaty programowania

Praktycznie całe zamieszanie dotyczące konwencji wywoływania funkcji kręci się w okół wskaźnika stosu.

1 Wskaźniki. 1.1 Główne zastosowania wskaźników

Zmienne i struktury dynamiczne

Wyrażenie wewnątrz nawiasów jest atomem (rozpatrujemy je jako całość).

Przez F(C) oznaczamy figurę narysowaną w kartezjańskim układzie współrzędnych, która ograniczona jest przez:

Programowanie i struktury danych

1. Wypisywanie danych

Algorytmy i język C++

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

#include <iostream> using namespace std; void ela(int); int main( ); { Funkcja 3. return 0; }

1 Wskaźniki i zmienne dynamiczne, instrukcja przed zajęciami

Wstęp do programowania

Wykład 8: klasy cz. 4

Wyjątki (exceptions)

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Zasady programowania Dokumentacja

TEMAT : KLASY DZIEDZICZENIE

1. Pierwszy program. Kompilator ignoruje komentarze; zadaniem komentarza jest bowiem wyjaśnienie programu człowiekowi.

> C++ wskaźniki. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki 26 kwietnia 2017

Wstęp do programowania. Wykład 1

Zadanie 2: Arytmetyka symboli

Programowanie obiektowe

Opis zagadnieo 1-3. Iteracja, rekurencja i ich realizacja

Programowanie proceduralne w języku C++ Pętle, tablice

Podstawy języka skryptowego Lua

Wykład II. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Laboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych.

O podstawowych operacjach na tablicach. Mateusz Ziółkowski, MBiU II

Aby uzyskać zaliczenie w pierwszym terminie (do 30 stycznia 2018) rozliczyć trzeba co najmniej 8 projektów, po 4 z każdej z części: C++ oraz Python.

Podstawy Programowania

Utworzenie pliku. Dowiesz się:

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Wstęp do informatyki- wykład 11 Funkcje

. Podstawy Programowania 2. Dwukierunkowa lista liniowa. Arkadiusz Chrobot. 7 kwietnia 2019

3. Instrukcje warunkowe

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

wykład IV uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C, a C++. wykład IV dr Jarosław Mederski Spis Język C++ - wstęp

Lista dwukierunkowa - przykład implementacji destruktorów

Przeciążenie (przeładowanie nazw) funkcji

r. Tablice podstawowe operacje na tablicach

// Potrzebne do memset oraz memcpy, czyli kopiowania bloków

Mechanizm dziedziczenia

Materiał Typy zmiennych Instrukcje warunkowe Pętle Tablice statyczne Wskaźniki Tablice dynamiczne Referencje Funkcje

Użycie filtrów w widoku

Metody Metody, parametry, zwracanie wartości

Wstęp do programowania

Jak Windows zarządza pamięcią?

Język C++ wykład VIII

Podstawy informatyki. Elektrotechnika I rok. Język C++ Operacje na danych - wskaźniki Instrukcja do ćwiczenia

Wstęp do Programowania 2

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

Programowanie obiektowe i C++ dla matematyków

Programowanie obiektowe

Listy i funkcje zaprzyjaźnione w C++

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk. Wydział Inżynierii Metali i Informatyki Przemysłowej

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych

PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH. KL IV TI 6 godziny tygodniowo (6x15 tygodni =90 godzin ),

Programowanie w języku C++

Wstęp do programowania

Programowanie proceduralne w języku C++ Podstawy

Zajęcia nr 5 Algorytmy i wskaźniki. dr inż. Łukasz Graczykowski mgr inż. Leszek Kosarzewski Wydział Fizyki Politechniki Warszawskiej

Wykład 1. Program przedmiotu. Programowanie Obiektowe (język C++) Literatura. Program przedmiotu c.d.:

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Transkrypt:

Lista jednokierunkowa jest strukturą o dynamicznie zmieniającej się wielkości. Listę można opisać jako uszeregowany zbiór elementów. Każdy element zawiera jakieś dane oraz wskazuje na swojego następcę. Cechą listy jednokierunkowej jest to, że można przeglądać ją tylko w jedną stronę, od początku do końca. Jak napisać listę jednokierunkową? Lista jednokierunkowa w odróżnieniu od tablicy jest rozrzucona po pamięci aplikacji. Jej elementy nie występują kolejno po sobie. Element poprzedni wskazuje na element następny. Dlatego tak ważne jest przypisywanie odpowiednich wskaźników do nowych elementów. Nie ma jednego rozwiązania dotyczącego zaimplementowania listy. Każda lista może być zbudowana w inny sposób, zależy to od programisty oraz programu. Ja tworząc listę posługuję się taką metodą: tworzę strukturę odpowiadającą jednemu elementowi listy element zawiera różne informacje np: imię, nazwisko, wiek oraz wskaźnik do następnego elementu. tworzę strukturę główną jest to struktura bazowa dla wszystkich elementów listy. Zawiera on adres początku listy czyli pierwszego elementu. Oprócz tego może zawierać różne metody typu np. dodawanie, sortowanie i usuwanie elementów. Tak wygląda zobrazowanie mojej koncepcji: Wszystkie ważne metody związane z listą umieszczam w strukturze głównej, zaznaczonej kolorem żółtym na rysunku. Inny popularny sposób tworzenia list jednokierunkowych w C++ mówi, aby funkcje związane z listą umieszczać całkiem poza Karol Trybulec p-programowanie.pl

strukturami związanymi z listą. Wtedy najważniejszym argumentem każdej funkcji operującej na liście jest wskaźnik do jej pierwszego elementu. Nie będę zajmował się drugą metodą, uważam że nie jest tak wygodna jak metoda zaprezentowana na obrazku wyżej. W mojej osobistej opinii: trzymając się zasad programowania obiektowego powinniśmy wszystkie metody odpowiedzialne za listę zgrupować w jednej strukturze/klasie a nie rozrzucać po całym programie. Żadne rozwiązanie nie jest błędne ani nie jest złe. Obydwa rozwiązania przedstawiają listy jednokierunkowe, różnią się tylko implementacją oraz w następstwie sposobem inicjacji i budowy listy, co jest logiczne. Gdy nabierzesz wprawy nie będziesz się nawet nad nimi zastanawiał, przyjmiesz własną koncepcję i będziesz się jej trzymał. Jeżeli w programie będziesz używał kilku list, wtedy wygodnie trzymać się powyższej metody. Jeżeli natomiast Twój program będzie korzystał z dziesiątek, setek list, wtedy warto operacje dotyczące list zaimplementować osobno, przekazując im jako argument wskaźnik na tę listę, na jakiej chcemy operować. Oszczędzi to miejsce w kodzie. Deklaracja struktury elementów oraz listy Stworzę listę służącą jako baza danych, będzie ona przechowywać imiona, nazwiska oraz wiek osób. Będę posługiwał się moją metodą przedstawioną na pierwszym rysunku w artykule. Pierwszym krokiem będzie utworzenie struktury elementu listy na dane i wskaźnik do kolejnego elementu. Druga struktura będzie odpowiedzialna za początek listy oraz metody. 0 struct osoba string imie; string nazwisko; int wiek; osoba *nastepna; osoba(); ; osoba::osoba() nastepna = 0; // wskaźnik na następny element // konstruktor // konstruktor struct lista osoba *pierwsza; // wskaźnik na początek listy void dodaj_osobe (string imie, string nazwisko, int wiek); void usun_osobe (int nr); void wyswietl_liste (); lista(); ; lista::lista() pierwsza = 0; // konstruktor Karol Trybulec p-programowanie.pl

Dodawanie elementów do listy Posiadamy potrzebne struktury. Do struktury lista, dodałem metodę dodaj_osobe, dzięki niej będziemy mogli dodawać osoby do naszej bazy. Co się dzieje gdy dodamy nową osobę (nowy element listy)? Ostatniemu elementowi listy przypisujemy wskaźnik na nasz nowo utworzony element i wypełniamy go danymi. Szczególną sytuacją jest moment kiedy dodajemy pierwszy element, wtedy nie można poprzednikowi ustawić wskaźnika, ponieważ poprzednika jeszcze nie ma. Przeanalizuj dokładnie poniższy kod ponieważ jego zrozumienie jest kluczowe: 0 0 void lista::dodaj_osobe(string imie, string nazwisko, int wiek) osoba *nowa = new osoba; // tworzy nowy element listy // wypełniamy naszymi danymi nowa->imie = imie; nowa->nazwisko = nazwisko; nowa->wiek = wiek; if (pierwsza==0) // sprawdzamy czy to pierwszy element listy // jeżeli tak to nowy element jest teraz początkiem listy pierwsza = nowa; else // w przeciwnym wypadku wędrujemy na koniec listy while (temp->nastepna) // znajdujemy wskaźnik na ostatni element temp = temp->nastepna; temp->nastepna = nowa; // ostatni element wskazuje na nasz nowy nowa->nastepna = 0; // ostatni nie wskazuje na nic Używanie listy jednokierunkowej czy nawet listy dwukierunkowej to tak naprawdę dobre zrozumienie wskaźników. Nie mamy iteratora aby odwoływać się do poszczególnych elementach tak jak w tablicy, do każdej operacji musimy znaleźć wskaźnik. Kiedy chciałem dodać nową osobę do bazy danych, musiałem za pomocą pętli while znaleźć wskaźnik do Karol Trybulec p-programowanie.pl

ostatniego elementu listy i dopiero wtedy dodać nowy element. Aby przyśpieszyć niektóre operacje na liście, można zapisywać wskaźnik do jej ostatniego elementu w głównej strukturze odpowiedzialnej za hierarchie listy (teraz zapisujemy tylko początek). Wyświetlanie elementów listy Aby wyświetlić dowolny element listy musimy znaleźć wskaźnik. Wędrówkę zaczynamy zawsze od początku listy. 0 int main() lista *baza = new lista; //tworzymy liste //dodajemy rekordy do bazy baza->dodaj_osobe("maciej","pierwszy", ); baza->dodaj_osobe("arkadiusz","drugi", ); baza->dodaj_osobe("dariusz","trzeci", ); baza->dodaj_osobe("andrzej","czwarty", ); // wyswietlamy osobę - macieja cout << baza->pierwsza->imie << endl; // wyswietlamy osobę - arkadiusza cout << baza->pierwsza->nastepna->imie << endl; // wyswietlamy wiek osoby - dariusza cout << baza->pierwsza->nastepna->nastepna->wiek << endl; // wyswietlamy wiek osoby - andrzeja cout << baza->pierwsza->nastepna->nastepna->nastepna->wiek << endl; delete (baza); return 0; Po uruchomieniu kodu strumień wyjścia wygląda następująco: Karol Trybulec p-programowanie.pl

Powyższy kod to tylko demonstracja, w jaki sposób poruszając się wskaźnikami po elementach listy wydobywamy informacje. Nie powinno się wyświetlać elementów listy w ten sposób, powinna być od tego osobna metoda a wskaźniki najlepiej przewijać w pętli while tak jak jest to pokazane w załączonej metodzie wyżej. Napiszmy proste ciało metody wyswietl_liste(). Sprawa jest trywialna, po wywołaniu metody, wyświetlamy w pętli wszystkie elementy listy przewijając wskaźnik w pętli: void lista::wyswietl_liste() // wskaznik na pierszy element listy // przewijamy wskazniki na nastepne elementy while (temp) cout << "imie: " << temp->imie << " nazwisko: " << temp->nazwisko << endl; temp=temp->nastepna; Usuwanie elementów listy Usuwając elementy listy jednokierunkowej należy pamiętać o porządku we wskaźnikach: jeżeli usuwasz pierwszy element (głowa/head) wystarczy ustawić nowy początek listy z elementu n na n+ jeżeli usuwasz środkowy element usuwając n-ty element trzeba uzyskać sytuację aby element n- wskazywał na element n+. Element n-ty można także usunąć z pamięci free lub delete jeżeli usuwasz ostatni element (ogon/tail) przyjmując że n-ty element znajduje się na końcu listy, usuwając go wystarczy wyzerować wskaźnik elementu n-. Zależnie od rodzaju aplikacji programista decyduje co jest kryterium w usuwaniu elementów listy, może być to unikalny id lub inny atrybut np. imie. Przykładowy kod odpowiedzialny za usuwanie elementu listy jednokierunkowej może wyglądać następująco: Karol Trybulec p-programowanie.pl

0 0 0 void lista::usun_osobe (int nr) // jezeli to pierwszy element listy if (nr==) pierwsza = temp->nastepna; //poczatek listy, el. wskazuje na el. itd.. // jeżeli nie jest to pierwszy element if (nr>=) int j = ; // do usuniecia srodkowego elemetnu potrzebujemy wskaznika na osobe n- // wskaznik *temp bedzie wskaznikiem na osobe poprzedzajaca osobe usuwana while (temp) // sprawdzamy czy wskaznik jest na osobie n- niz usuwana if ((j+)==nr) break; // jezeli nie to przewijamy petle do przodu temp = temp->nastepna; j++; // wskaznik *temp wskazuje teraz na osobe n- // nadpisujemy wkaznik osoby n na osobe n+ // bezpowrotnie tracimy osobe n-ta // dodatkowo sprawdzamy czy aby nie jest to ostatni element // wtedy nalezy wyzerowac ostatni wskaznik if (temp->nastepna->nastepna==0) temp->nastepna = 0; // jezeli nie byl to ostatni element else temp->nastepna = temp->nastepna->nastepna; Kryterium według którego usuwamy elementy jest ich numer na liście (numerując od..n a nie od 0 tak jak tablice). Co sądzisz o tej metodzie? Wydaje się lekko skomplikowana, szczególnie przewijanie wskaźników dla elementów środkowych. Można to uprościć. Swego czasu pisząc rozbudowany projekt z listą jednokierunkową stworzyłem specjalną metodę, która Karol Trybulec p-programowanie.pl

zwracała mi wskaźnik na element n-. Kod znacząco się skrócił piszcząc poszczególne funkcjonalności listy, ponieważ nie musiałem przewijać wszystkich elementów w poszukiwaniu wskaźnika n- dostawałem go od razu po wywołaniu metody. Podsumowanie Lista jednokierunkowa z prawdziwego zdarzenia powinna posiadać jeszcze inne metody np. dodawanie elementów na początek/koniec, sortowanie, wyszukiwanie.. Reszta funkcji zależy od aplikacji jaką piszemy. W internecie jest wiele gotowych list z dołączonymi metodami. Ten artykuł miał pokazać na jakiej zasadzie tworzyć i budować listę dlatego przedstawiłem tylko podstawowe metody. Uwaga! W artykule podczas usuwania elementów listy, po prostu pozbywałem się wskaźników natomiast nie usuwałem obiektów w pamięci na które wskazywały wskaźniki. Może to powodować błędy memory-leak w rozbudowanych aplikacjach. Pisząc projekt na zaliczenie, przypuszczam że nie ma to żadnego znaczenia. Nie usuwałem wskaźników z pamięci, ponieważ kod został by znacznie zaśmiecony. Jeżeli chcesz skompilować plik dołączony przeze mnie na samym dole strony, rozważ na jakim środowisku go uruchamiasz. Na poszczególnych kompilatorach różnią się nieco biblioteki dyrektywy #include. Microsoft Visual Studio: #include "stdafx.h" #include <iostream> #include <string> using namespace std; Pozostałe (np. Code::Blocks): #include <iostream> #include <string> #include <cstdlib> using namespace std; Kompletny kod można pobrać pod adresem: http://www.p-programowanie.pl/pliki/lista_jednokierunkowa.cpp Karol Trybulec p-programowanie.pl