r. Tablice podstawowe operacje na tablicach

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

ZASADY PROGRAMOWANIA KOMPUTERÓW

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

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

Tablice. Monika Wrzosek (IM UG) Podstawy Programowania 96 / 119

Programowanie komputerowe. Zajęcia 1

MACIERZE. Sobiesiak Łukasz Wilczyńska Małgorzata

1 Podstawy c++ w pigułce.

tablica: dane_liczbowe

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

Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4. Wskaźniki. Dynamiczna alokacja pamięci. Przykłady

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

Zmienne i struktury dynamiczne

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

typ y y p y z łoż o on o e n - tab a lice c e w iel e owym m ar a o r we, e stru r kt k ury

Wstęp do programowania. Wykład 1

Lab 9 Podstawy Programowania

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

INFORMATYKA Z MERMIDONEM. Programowanie. Moduł 5 / Notatki

> C++ dynamiczna alokacja/rezerwacja/przydział pamięci. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki

Programowanie - wykład 4

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

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:

Część 4 życie programu

Liczby całkowite i rzeczywiste

Deklaracja struktury w C++

Podstawy Programowania

TABLICA (ang. array) pojedyncza zmienna z wieloma komórkami, w których można zapamiętać wiele wartości tego samego typu danych.

Programowanie obiektowe W3

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 16 kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 27

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.

DYNAMICZNE PRZYDZIELANIE PAMIECI

Dla każdej operacji łącznie tworzenia danych i zapisu ich do pliku przeprowadzić pomiar czasu wykonania polecenia. Wyniki przedstawić w tabelce.

Inicjacja tablicy jednowymiarowej

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

Niezwykłe tablice Poznane typy danych pozwalają przechowywać pojedyncze liczby. Dzięki tablicom zgromadzimy wiele wartości w jednym miejscu.

1 Podstawy c++ w pigułce.

Algorytmika i programowanie. Wykład 2 inż. Barbara Fryc Wyższa Szkoła Informatyki i Zarządzania w Rzeszowie

Podstawy programowania. Wykład: 6. Tablice statyczne. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

Podstawy Programowania Podstawowa składnia języka C++

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

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 26 marca kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 40

Materiał. Typy zmiennych Instrukcje warunkowe Pętle Tablice statyczne Funkcje Wskaźniki Referencje Tablice dynamiczne Typ string Przeładowania funkcji

I - Microsoft Visual Studio C++

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

Wymiar musi być wyrażeniem stałym typu całkowitego, tzn. takim, które może obliczyć kompilator. Przykłady:

Pytania sprawdzające wiedzę z programowania C++

Tablice mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

Programowanie w języku C++

8. Wektory. Przykłady Napisz program, który pobierze od użytkownika 10 liczb, a następnie wypisze je w kolejności odwrotnej niż podana.

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

Jak napisać program obliczający pola powierzchni różnych figur płaskich?

(3 kwiecień 2014) Marika Pankowska Kamila Pietrzak

Programowanie komputerowe. Zajęcia 4

Wstęp do programowania

Wieczorowe Studia Licencjackie Wrocław, Wykład nr 6 (w oparciu o notatki K. Lorysia, z modyfikacjami) Sito Eratostenesa

Jak Windows zarządza pamięcią?

Programowanie komputerowe. Zajęcia 3

Programowanie i struktury danych

Język C zajęcia nr 11. Funkcje

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

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

Transponowanie macierzy Mnożenie macierzy Potęgowanie macierzy Wyznacznik macierzy

Wstęp do programowania INP001213Wcl rok akademicki 2018/19 semestr zimowy. Wykład 4. Karol Tarnowski A-1 p.

Wstęp do programowania

C++ wprowadzanie zmiennych

C++ - [1-3] Debugowanie w Qt Creator

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

Podstawy Informatyki. Inżynieria Ciepła, I rok. Wykład 10 Kurs C++

do instrukcja while (wyrażenie);

Informacje wstępne #include <nazwa> - derektywa procesora umożliwiająca włączenie do programu pliku o podanej nazwie. Typy danych: char, signed char

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

Podstawy algorytmiki i programowania - wykład 4 C-struktury

Zadania do wykonania. Rozwiązując poniższe zadania użyj pętlę for.

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

STL: Lekcja 1&2. Filozofia STL

7. Pętle for. Przykłady

Wykład 8: klasy cz. 4

Pętle i tablice. Spotkanie 3. Pętle: for, while, do while. Tablice. Przykłady

Podstawy Programowania C++

Podstawy programowania 2. Temat: Wprowadzenie do wskaźników. Przygotował: mgr inż. Tomasz Michno

Wykład II Tablice (wstęp) Przykłady algorytmów Wstęp do języka C/C++

Wstęp do informatyki- wykład 7

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

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

Programowanie obiektowe i C++ dla matematyków

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

Wstęp do programowania

Języki programowania obiektowego Nieobiektowe elementy języka C++

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

Programowanie C++ Wykład 2 - podstawy języka C++ dr inż. Jakub Możaryn. Warszawa, Instytut Automatyki i Robotyki

Struktury Struktura polami struct struct struct struct

Wstęp do programowania INP003203L rok akademicki 2018/19 semestr zimowy. Laboratorium 2. Karol Tarnowski A-1 p.

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

- - Ocena wykonaniu zad3. Brak zad3

1 P roste e t ypy p d a d n a ych c - c ąg ą g d a d l a szy 2 T y T py p z ł z o ł żo ż ne e d a d n a ych c : T BLICE

Globalne / Lokalne. Wykład 15. Podstawy programowania (język C) Zmienne globalne / lokalne (1) Zmienne globalne / lokalne (2)

Wskaźniki. Informatyka

Podstawy programowania w C++

Programowanie strukturalne i obiektowe. Funkcje

Transkrypt:

27.03.2014r. Tablice podstawowe operacje na tablicach

Tablica - definicja Tablica (ang. array) lub wektor (ang. vector) jest złożoną strukturą danych (ang. compound data structure) zbudowaną z ciągu elementów tego samego typu. W pamięci komputera elementy tablicy są ułożone kolejno jeden obok drugiego. Dostęp do elementu odbywa się poprzez numer zwany indeksem. Na podstawie indeksu, rozmiaru elementu oraz adresu początku tablicy komputer oblicza adres elementu i w ten sposób uzyskujemy do niego dostęp.

We współczesnych językach programowania tablice są stosowane powszechnie do przechowywania danych podobnego rodzaju. Przy ich pomocy można zapisywać ciągi liczbowe, wyniki pomiarów różnych wielkości oraz tworzyć złożone bazy danych. Liczba zastosowań tablic jest w zasadzie ograniczona naszą wyobraźnią. Podstawową zaletą tablic jest prostota przetwarzania ich elementów. Dzięki dostępowi poprzez indeksy, elementy tablic daje się łatwo przetwarzać w pętlach iteracyjnych.

Deklarowanie tablic Deklarację tablicy umieszczamy w języku C++ na liście deklaracji zmiennych. Składnia jest następująca: typ_danych nazwa_tablicy[liczba_elementów]; typ_danych określa rodzaj informacji przechowywanych przez deklarowane zmienne nazwa_tablicy tworzona jest wg zwykłych reguł tworzenia nazw zmiennych w języku C++ Liczba_elementów przechowuje tablica określa, ile elementów danego typu

W języku C++ indeksy tablic rozpoczynają się od 0. Ma to sens, ponieważ nazwa tablicy jest traktowana zawsze jak adres początku obszaru pamięci, w którym tablica przechowuje swoje elementy. Naturalne zatem jest, iż pierwszy element leży właśnie pod adresem tablicy. Stąd jego indeks wynosi 0, czyli nic nie musimy dodawać do adresu początku tablicy, aby uzyskać dostęp do jej pierwszego elementu.

Przykłady deklaracji tablic w C++ : int a[3]; // tablica zawierająca 3 elementy typu int double x[10]; // tablica przechowująca 10 liczb typu double char c[6]; // tablica przechowująca 6 wartości znakowych W powyższym przykładzie zadeklarowano trzy tablice a, x oraz c. Posiadają one elementy o następujących indeksach: Tablica a : a[0] a[1] a[2] - 3 elementy typu integer Tablica x : x[0] x[1] x[2] x[3] x[4] x[5] x[6] x[7] x[8] x[9] - 10 elementów typu double Tablica c : c[0] c[1] c[2] c[3] c[4] c[5] - 6 elementów typu char

Zwróć uwagę, iż tablica nie posiada elementu o indeksie równym ilości elementów. Zatem jeśli zadeklarujemy np. tablicę: double Tlk[168]; to jej ostatnim elementem jest Tlk[167], a nie Tlk[168]. Odwołanie się w programie do Tlk[168] jest błędem,

Inicjalizacja tablic Często zdarza się, iż chcemy utworzyć tablicę z zadaną z góry zawartością (np. tablica zawierająca początkowe liczby pierwsze). Składnia inicjalizacji tablicy w języku C++ jest następująca: typ_elementów nazwa_tablicy = {lista_wartości_dla_kolejnych_elementów}; Zwróć uwagę, iż nie musimy podawać liczby elementów. Kompilator utworzy tyle elementów, ile podamy dla nich wartości na liście inicjalizacyjnej. Poniższy przykład tworzy tablicę 10 liczb całkowitych i wypełnia ją kolejnymi liczbami Fibonacciego. int fib[] = (0,1,1,2,3,5,8,13,21,33);

Tablice dynamiczne Zdarza się, iż w trakcie pisania programu nie wiemy, ile dokładnie elementów będzie zawierała używana w tym programie tablica. W takim przypadku problem tworzenia tablicy możemy rozwiązać na dwa sposoby: 1. Utworzyć tablicę o maksymalnej, przewidywanej liczbie elementów. Rozwiązanie nieefektywne ze względu na wykorzystanie pamięci. Jeśli w typowych przypadkach wykorzystujemy małą liczbę elementów tablicy, to i tak musimy rezerwować założoną ilość komórek dla przypadku pesymistycznego, który pojawia się bardzo rzadko, ale jest prawdopodobny. 2. Utworzyć tablicę dynamicznie o tylu komórkach, ile w danej chwili jest nam potrzebne. Po wykorzystaniu, tablicę dynamiczną usuwamy, zwalniając w ten sposób zajmowany przez nią obszar pamięci, który teraz można wykorzystać do innych celów np. dla nowej tablicy dynamicznej.

W celu utworzenia w języku C++ tablicy dynamicznej, tworzymy zmienną wskaźnikową na typ danych, które mają być przechowywane w tablicy: typ_elementów * nazwa_tablicy_dynamicznej; Zmienna wskaźnikowa (ang. pointer variable) nie przechowuje danych tylko adres obszaru pamięci komputera, w którym te dane się znajdują. Deklarację zmiennej wskaźnikowej zawsze poprzedzamy znakiem gwiazdki. W poniższym przykładzie tworzymy trzy wskaźniki a, b i c do danych typu double (czyli do obszaru pamięci, w którym będą przechowywane liczby zmiennoprzecinkowe o podwójnej precyzji): double * a, * b, * c;

Pamięć rezerwujemy operatorem new i adres zarezerwowanego obszaru umieszczamy w zmiennej wskaźnikowej: nazwa_tablicy_dynamicznej = new typ_elementów[liczba_elementów]; Poniższy przykład tworzy trzy tablice dynamiczne, w których będzie można przechowywać odpowiednio 10, 100 i 1000 elementów typu double: a = new double[10]; // elementy od a[0] do a[9] b = new double[100]; // elementy od b[0] do b[99] c = new double[1000]; // elementy od c[0] do c[999]

Po tej operacji do elementów tablic a, b i c odwołujemy się w zwykły sposób za pomocą indeksów. Istnieje również alternatywna metoda, wykorzystująca fakt, iż zmienne a, b i c są wskaźnikami. W języku C++ dodanie do wskaźnika liczby całkowitej powoduje obliczenie adresu elementu o indeksie równym dodawanej liczbie. Zatem wynik takiej operacji jest również wskaźnikiem: Tablica a[2] = 10.54; cout << a[2] << endl; Wskaźnik *(a + 2) = 10.54; cout << * (a + 2) << endl;

#include <iostream> using namespace std; int main() { double * a[2]; wskaźnik // definiujemy a[2] = new double; // przydzielamy pamięć * a[2] = 10.54; // w przydzielonej pamięci umieszczamy dane cout << * a[2] << endl; delete a[2]; // zwalniamy przydzielony obszar pamięci } return 0;

W rzeczywistości zapis a[i] kompilator i tak przekształca sobie na zapis * (a + i). Forma tablicowa jest tylko uproszczeniem zapisu wskaźnikowego. Tablice dynamiczne nie są automatycznie usuwane z pamięci, jeśli utworzono je w funkcji. Dlatego po zakończeniu korzystania z tablicy program powinien zwolnić zajmowaną przez tablicę pamięć. Dokonujemy tego poleceniem delete w sposób następujący: delete [] nazwa_tablicy_dynamicznej;

W poniższym przykładzie zwalniamy pamięć zarezerwowaną wcześniej na elementy tablic b i c. delete [] b; // usuwamy obszar wskazywany przez b delete [] c; // usuwamy obszar wskazywany przez c

Należy również wspomnieć, iż Code::Blocks dopuszcza konstrukcję: typ_elementów nazwa_tablicy[zmienna]; co pozwala na tworzenie statycznych tablic o liczbie elementów podanej w zmiennej. Na przykład poniższa konstrukcja programowa tworzy statyczną tablicę a o liczbie elementów odczytanej ze strumienia wejściowego konsoli znakowej: int n; cin >> n; double a[n]; Jednakże nie jest to zbyt standardowe rozwiązanie i może nie być przenośne na inne kompilatory C++, dlatego odradzam używania go lepiej zastosować tablicę dynamiczną.

Tablice dynamiczne o dynamicznym rozmiarze Gdy operujemy na dynamicznych strukturach danych, to często okazuje się, że taką strukturę należy zwiększyć lub zmniejszyć w czasie działania programu. Np. utworzyliśmy na początku algorytmu dynamiczną tablicę 100 elementową, lecz dalej okazało się, że w tablicy tej należy dodatkowo umieścić jeszcze 50 kolejnych elementów. Co możemy zrobić? Odpowiedź jest prosta dynamicznie zmienić rozmiar naszej struktury. Zasada jest następująca:

Oprócz wskazania do tablicy tworzymy dodatkową zmienną, która przechowuje jej maksymalny rozmiar. Oznaczmy tę zmienną przez nn. Każdą tablicę tworzymy z pewnym zapasem komórek, oznaczmy go przez z. Zmienna n przechowuje informację o ilości zajętych komórek.

Gdy dodajemy element do tablicy, to najpierw zwiększamy n o 1 i sprawdzamy, czy warunek n >= nn jest spełniony. Jeśli tak, to tablica zawiera za mało komórek, i należy zwiększyć jej rozmiar. Operację tę przeprowadzamy następująco: 1. Rezerwujemy nowy obszar pamięci o rozmiarze nn + z i zapamiętujemy jego adres w tymczasowej zmiennej. 2. Przepisujemy zawartość starego obszaru tablicy do nowego. 3. Usuwamy stary obszar w ten sposób system odzyska pamięć. 4. Do wskaźnika tablicy przepisujemy adres ze zmiennej tymczasowej. 5. Zmienną nn zwiększamy o z

Zwróć uwagę, że cała tablica zmieniła swoje położenie w pamięci. Jeśli zatem posiadałeś jakieś zmienne, które przechowywały adresy jej elementów (wskaźniki), to teraz przestaną one być aktualne, ponieważ wskazują stary obszar, który już do tej tablicy nie należy (chociaż przez pewien czas może zachowywać swoją zawartość aż system zapisze go innymi danymi). Należy to wziąć pod uwagę, gdy planujesz wykorzystywanie dynamicznych tablic o dynamicznym rozmiarze.

if(++n >= nn) { typ_danych * T = new typ_danych[nn+z]; for(int i = 0; i < nn; i++) T[i] = A[i]; delete [] A; A = T; nn += z; }

Przy usuwaniu elementów z tablicy postępujemy podobnie. Gdy usuniemy element, to rozmiar tablicy n zostanie zmniejszony o 1. Sprawdzamy, czy jest spełniony warunek n nn - 2z. Jeśli tak, to tablica zajmuje zbyt duży obszar i powinniśmy zmniejszyć jej rozmiar. Dlaczego w nierówności użyliśmy 2z a nie po prostu z? Chodzi o to, aby po zmniejszeniu rozmiaru tablica wciąż posiadała zapas z komórek, co zmniejszy ryzyko częstych przeładowań pamięci, które są przecież kosztowne czasowo. Zmianę rozmiaru tablicy wykonujemy podobnie jak przy zwiększaniu liczby elementów:

if(--n <= nn-z-z) { typ_danych * T = new typ_danych[nn-z]; for(int i = 0; i < n; i++) T[i] = A[i]; delete [] A; A = T; nn -= z; }

Wprowadzanie/wyprowadzanie danych Dane dla programu zwykle muszą być odczytywane ze zewnętrznego źródła konsoli lub pliku. W takim przypadku nie wiemy z góry (tzn. w trakcie pisania programu) ile ich będzie. Narzucającym się rozwiązaniem jest zastosowanie tablic dynamicznych. Ze źródła danych odczytujemy rozmiar tablicy, tworzymy tablicę dynamiczną o odpowiednim rozmiarze, a następnie wczytujemy do jej komórek poszczególne dane. Poniżej podajemy sposoby odczytu zawartości tablicy z konsoli. Sposób ten jest bardzo ogólny. Wykorzystanie standardowego wejścia jako źródła danych daje nam kilka możliwości wprowadzania danych:

I sposób Dane podajemy bezpośrednio z klawiatury. Sposób skuteczny i prosty dla niedużego zbioru danych. Jednakże przy większej ich liczbie staje się bardzo uciążliwy.

II sposób Skopiowanie danych poprzez schowek. Procedura postępowania jest następująca: tworzymy w notatniku Windows (aplikacja zawsze pod ręką) odpowiedni zbiór danych zbiór kopiujemy do schowka (zaznaczamy całość Ctrl-A i naciskamy Ctrl-C) uruchamiamy program klikamy prawym przyciskiem myszki w pasek tytułowy okna konsoli z menu kontekstowego wybieramy polecenie Edytuj Wklej gotowe

III sposób Przekierowanie standardowego wejścia z konsoli na plik na dysku. W tym przypadku program będzie pobierał dane z pliku, a nie z klawiatury. Aby to uzyskać uruchamiamy program w oknie konsoli następująco: nazwa_programu < nazwa_pliku_wejściowego Na przykład nasz program nazywa się szukaj.exe, a plik nosi nazwę dane.txt. Odpowiednie polecenie odczytu danych z pliku przez nasz program wygląda następująco: szukaj < dane.txt To rozwiązanie umożliwia również zapis danych wynikowych nie na ekran konsoli, lecz do pliku na dysku. W tym celu wystarczy wydać polecenie: nazwa_programu > nazwa_pliku_wynikowego Wejście i wyjście można przekierować w jednym poleceniu. Np. nasz program szukaj może odczytać dane wejściowe z pliku dane.txt, a wyniki swojej pracy umieścić w pliku wyniki.txt. W tym celu wydajemy takie oto polecenie: szukaj < dane.txt > wyniki.txt

Program Program z pierwszego wiersza odczytuje liczbę n określającą ilość danych. Z następnych n wierszy odczytywane są dane i umieszczane w tablicy dynamicznej. Odczytane dane zostają następnie wyświetlone jedna obok drugiej. Wypróbuj z tym programem podane powyżej trzy opcje dostarczania danych i wyprowadzania wyników.

#include <iostream> using namespace std; int main() { int * T,n,i; cin >> n; T = new int[n]; for(i = 0; i < n; i++) cin >> T[i]; cout << endl; for(i = 0; i < n; i++) cout << T[i] << " "; cout << endl << endl; delete [] T; } return 0;

Wypełniane tablicy Czasami algorytm musi wstępnie wypełnić tablicę określoną zawartością. Operację taką przeprowadza się w pętli iteracyjnej, której zmienna licznikowa przebiega przez wszystkie kolejne indeksy elementów. Następnie wykorzystuje się zmienną licznikową jako indeks elementu tablicy, w którym umieszczamy określoną zawartość. W poniższych przykładach zakładamy, iż w programie zadeklarowano tablicę T o 100 elementach typu integer. Indeksy elementów tablicy T są w zakresie od 0 do 99.

Wypełnianie liczbami parzystymi począwszy od 2... for(i = 0; i < 100; i++) T[i] = (i + 1) << 1;...

Wypełnianie liczbami nieparzystymi począwszy od 1... for(i = 0; i < 100; i++) T[i] = 1 + (i << 1);...

Wypełnianie liczbami pseudolosowymi z przedziału <a,b> #include <cstdlib> #include <time.h>... srand((unsigned)time(null));... for(i = 0; i < 100; i++) T[i] = a + rand() % (b - a + 1);...