Professional Documents
Culture Documents
Wykład 2
Podstawy struktur danych
Dynamiczne struktury danych
Implementacja dynamicznych struktur danych w języku C
Definicja struktury danych
Definicja
Strukturą danych nazywamy trójkę uporządkowaną S=(D, R,
e),
gdzie:
D – oznacza zbiór danych elementarnych di, i = 1,..,d
R={rwe, N} – jest zbiorem dwóch relacji określonych na
rwe ⊂ e × Ddanych:
strukturze
N ⊂ D× D – relacja wejścia do struktury danych S,
– relacja następstwa (porządkująca) strukturę
S,
■ d i = ni , wi , gdzie:
◆ ni – nazwa danej,
◆ wi – aktualna wartość danej z określonej dziedziny
wartości.
rwe = { e, d2 , e, d5 }
N = { d 2 , d1 , d1 , d 3 , d1 , d 4 , d 3 , d 4 , d 5 , d 3 }
poprzednik następnik
korzeń
Przykład: Model grafowy dla opisywanej do tej pory struktury S:
e d5
liść
d2 d3
D = { d1 , d 2 , d 3 , d 4 , d 5 }
rwe = { e, d 2 , e, d 5 }
d1
N = { d 2 , d1 , d1 , d 3 , d1 , d 4 , d 3 , d 4 , d 5 , d 3 }
korzeń
d4
Wskaźnik Zmienna
Adres Wartość
Deklaracja wskaźnika:
typ *nazwa;
Przykłady:
int *wsk1;
char *wsk2;
Przykład
#include <stdio.h>
int main(void)
{
int *p, q;
q = 100; /* przypisanie do q wartości 100 */
p = &q; /* przypisanie do p adresu q */
printf("%d", *p); /* wyświetlenie wartości q z użyciem
wskaźnika */
return 0;
}
Przykład
#include <stdio.h>
int main(void)
{
int *p, q;
p = &q; /* pobranie adresu q */
*p = 100; /* przypisanie wartości q z wykorzystaniem
wskaźnika */
printf(„wartośćią q jest %d", q);
return 0;
}
Jeżeli mamy:
int *p;
p=p+200;
to p będzie wskazywało na 200. liczbę całkowitą występująca za liczbą
wskazywaną poprzednio.
Podobnie działają operatory odejmowania.
Zadanie
Jaka wartość zostanie wypisana na ekranie?
Odpowiedź: 8
Algorytmy i struktury danych 24
Wskaźniki i tablice
Zadanie
Napisać program wczytujący ciąg znaków. Program
powinien odszukać pierwszą spację w ciągu, a następnie
wyświetlić pozostałą część napisu występującą za nią.
Wykorzystać zmienne wskaźnikowe.
int main(void)
{
char str[80], *p;
printf(„Wprowadź ciąg znaków: ");
gets(str);
p = str;
/* Dopóki nie natrafimy na koniec napisu lub spację,
zwiększamy p aby pobrać następny znak */
while(*p && *p!=' ') p++;
p++;
printf(p); Uruchom program
return 0;}
char **mp;
newPtr ?
dane nextPtr
■
Przykład:
struct node *newPtr;
■ W języku C++ :
◆ do alokacji pamięci można używać polecenia new,
np.
struct node *robPtr;
robPtr=new struct node;
◆ do zwalniania pamięci można używać polecenia
delete, np.
delete robPtr;
Wykład 3
Liniowe struktury danych (listy)
Rodzaje struktur liniowych
Implementacja list
Podstawowe operacje na listach jednokierunkowych
Liniowe struktury danych
d1 d2 d3 dn
d1 d2 d3 dn
d1 d2 d3 dn
e
d2
d1 d3
dn
NULL
startPtr
A B C D
■ Przykład:
Node *element = Find (startPtr, ‘C’);
Wartość szukana: C
prevPtr NULL newPtrcurrPtr: startPtr
currPtr -> dane: A
currPtr
currPtr C NULL
NULL
startPtr A B D
C D
NULL
Algorytmy i struktury danych 47
Dynamiczne realizacje struktur
listowych
■ Przykład (cd):
Node *element = Find (startPtr, ‘C’);
Nazwa szukana: C
prevPtr NULL newPtrcurrPtr: currPtr -> next
currPtr -> dane: B
currPtr currPtr C NULL
NULL
startPtr A B D
C D
NULL
Algorytmy i struktury danych 48
Dynamiczne realizacje struktur
listowych
■ Przykład (cd.)
Node *element = Find (startPtr, ‘C’);
Nazwa szukana: C
prevPtr NULL newPtrcurrPtr: currPtr -> next
currPtr -> dane: C
currPtr currPtr C NULL
NULL
startPtr A B D
C D
NULL
Algorytmy i struktury danych 49
Algorytm dołączania elementu do
uporządkowanej listy
jednokierunkowej
◆ Cel:
✦ Dodanie nowego elementu do listy uporządkowanej;
◆ Dane wejściowe:
✦ Wskaźnik na pierwszy element listy;
✦ Dane do wstawienia na listę;
startPtr A B D
Algorytmy i struktury danych 50
Algorytm dołączania elementu do uporządkowanej listy
jednokierunkowej
1. Utwórz element i ustal dane elementarne
2. Znajdź miejsce wstawienia elementu na listę
✦ Zainicjuj currPtr na początek listy a prevPtr na NULL;
✦ Dopóki currPtr jest różny od NULL i wartość wstawiana jest
większa od currPtr->dane:
• Ustaw prevPtr na currPtr;
• Przesuń currPtr na następny element listy;
3. Wstaw element na listę:
✦ Wstaw element jako pierwszy na liście:
• Ustaw pole next elementu wstawianego na pierwszy
element listy;
• Ustaw wskaźnik do listy na element wstawiony;
lub
✦ Wstaw element we wskazane miejsce w liście:
• Ustaw pole next elementu prevPtr na element wstawiany;
• Ustaw pole next elementu wstawianego na element
currPtr;
prevPtr newPtr
currPtr
startPtr A B D NULL
Algorytmy i struktury danych 52
1. Utwórz element i ustal dane
elementarne (cd.)
currPtr C NULL
startPtr A B D NULL
Algorytmy i struktury danych 53
2. Znajdź miejsce wstawienia elementu na
listę
Dopóki currPtr jest różny od NULL oraz dane elementu
wstawianego są ‘większe’ od currPtr->dane:
• Ustaw prevPtr na currPtr;
• Przesuń currPtr na następny element listy;
…
/* Znajdź miejsce wstawienia */
while ((currPtr != NULL) && (nazwa > currPtr-
>dane))
{
prevPtr = currPtr;
currPtr = currPtr -> next;
}
newPtr
prevPtr currPtr C N
ULL
startPtr A B D NULL
Algorytmy i struktury danych 54
3. Wstaw element na listę
if (prevPtr == NULL)
/* Wstaw element jako pierwszy w liście */
{
newPtr -> next = *startPtr;
*startPtr = newPtr;
}
newPtr
currPtr currPtr C NULL
NULL
startPtr A
C B
A D
B D
NULL
Algorytmy i struktury danych 55
3. Wstaw element na listę (cd.)
startPtr
startPtr AA BB DD
C D
NULL
NULL
Algorytmy i struktury danych 56
Algorytm dołączania elementu do listy
jednokierunkowej – pełny kod
int insert (NodePtr *startPtr, char nazwa)
{
struct Node *newPtr, *currPtr, *prevPtr;
int retcode=1;
/* Utwórz element Node */
newPtr = (struct Node *)malloc(sizeof(Node));
if (newPtr == NULL) /* weryfikacja przydzielonej pamięci*/
return 1;
else
{ /* Ustal dane elementarne w Node */
newPtr -> dane = nazwa;
newPtr -> next = NULL;
/* Zainicjowanie wskaźników pomocniczych */
currPtr = startPtr; /* ustaw wskaźnik na głowę listy */
prevPtr = NULL;
while ((currPtr != NULL) && (nazwa > currPtr->dane))
{
prevPtr = currPtr;
currPtr = currPtr -> next;
}
if (prevPtr == NULL) /* Wstaw element jako pierwszy w liście */
{
newPtr -> next = *startPtr;
*startPtr = newPtr;
}
else /* Wstaw element w miejsce między prevPtr a currPtr */
{
newPtr->next = currPtr;
prevPtr->next = newPtr;
}
}
return 0;
}
Uwagi:
◆ każdy element posiada dodatkowe pole (wskaźnik)
prev, który dla pierwszego elementu listy jest równe
NULL;
◆ lista może być przeglądana w obydwu kierunkach;
◆ często pamięta się dowiązania do pierwszego i
ostatniego elementu;
◆ należy zawsze uaktualniać dowiązania w obydwu
kierunkach;
◆ Cel:
✦ Usunięcie elementu z listy;
◆ Dane wejściowe:
✦ Wskaźnik na pierwszy element listy startPtr;
✦ Opis usuwanego elementu, np. wartość danej
elementarnej;
startPtr
Przed
usunięciem: A B C
startPtr
Po usunięciu: A B C
...
◆ Znajdź na liście element do usunięcia:
…
else
{ /* znajdź w liście element do usunięcia */
prevPtr = *startPtr; /* początek listy
*/
currPtr = (*startPtr)->next; /* drugi element*/
while (currPtr != NULL && currPtr -> dane !=
nazwa)
{
prevPtr = currPtr;
currPtr = currPtr -> next;
}