Sunteți pe pagina 1din 51

ALGORITMI

ȘI STRUCTURI DE DATE

Cap.8: Structuri de date secvențiale.


Tablouri, liste și iteratori
IE.2020
Plan
● (i) Structuri de date secvențiale
○ Tablouri
○ Liste inlănțuite
■ Simple/simplu înlănțuite
■ Circulare/circular înlănțuite
■ Double/dublu înlănțuite
● (ii) Liste și iteratori
○ Liste bazate tablouri
■ Tipul abstract Listă (interfața List)
■ Implementare bazată pe tablouri
○ Liste poziționale
■ Tipul abstract PositionalList
■ Implementări bazate pe liste înlănțuite
○ Liste iterative (Iteratori)
Structuri de date și tipuri abstracte
● O structură de date se referă la o modalitate concretă de gestionare și
accesare a datelor în memoria internă.
● Un tip abstract de date se referă la modul de operare asupra datelor:
abstractizarea unui set de operații (ce se poate face) față de modul concret
de acționare (cum se poate face).

Implementări exemplu: net.datastructures detaliate în Data Structures and Algorithms


in Java (Goodrich14) - vezi referințe bibliografice.
1. Structuri secvențiale: Tablouri [Arrays]
● Definiție: un tablou/array poate fi considerat o colecție secvențială de variabile
de același tip.
● Caracteristici (Java):
○ fiecare variabilă (celulă) este asociată unui index (poziție) unică;
○ fiecare valoare stocată (element) este accesibilă prin sintaxa a[k];
■ k < a.length - 1, length fiind capacitatea (fixă) a tabloului.
● Declarație tablou:
○ elementType[ ] arrayName = {initialValue0, initialValue1, . . . , initialValueN−1};
○ elementType[ ] arrayName = new elementType[length];
Aplicații cu tablouri: Scoreboard
● Gestiunea stocării elementelor într-un tablou: adăugare, inserare, ștergere.
● Aplicația “ScoreBoard” de gestiune a scorurilor pentru jocuri (video).
○ Cerințe/descriere:
■ reprezentare scoruri;
■ păstrarea (ordonată a) celor mai mari scoruri (renunțarea la scorurile cele mai slabe).
○ Structuri/clase de implementare
■ class GameEntry;
■ class Scoreboard.
Aplicații cu tablouri: Scoreboard
● Scheletul clasei GameEntry [extras (Goodrich14)]:
public class GameEntry {
private String name; // name of the person earning this score
private int score; // the score value
/** Constructs a game entry with given parameters.. */
public GameEntry(String n, int s) {
name = n;
score = s;
}
/** Returns the name field. */
public String getName() { return name; }
/** Returns the score field. */
public int getScore() { return score; }
/** Returns a string representation of this entry. */
public String toString() {
return "(" + name + ", " + score + ")";
}
}
Aplicații cu tablouri: Scoreboard
● Scheletul clasei Scoreboard:

/** Class for storing high scores in an array in nondecreasing order. */


public class Scoreboard {
private int numEntries = 0; // number of actual entries
private GameEntry[] board; // array of game entries (names & scores)
/** Constructs an empty scoreboard with the given capacity for storing entries. */
public Scoreboard(int capacity) {
board = new GameEntry[capacity];
}

}
Aplicații cu tablouri: Scoreboard
● Adăugarea unui nou element pe tabla de scoruri:
/** Attempt to add a new score to the collection (if it is high enough) */
public void add(GameEntry e) {
int newScore = e.getScore();
// is the new entry e really a high score?
if (numEntries < board.length || newScore > board[numEntries-1].getScore()) {
if (numEntries < board.length) // no score drops from the board
numEntries++; // so overall number increases
// shift any lower scores rightward to make room for the new entry
int j = numEntries - 1;
while (j > 0 && board[j-1].getScore() < newScore) {
board[j] = board[j-1]; // shift entry from j-1 to j
j--; // and decrement j
}
board[j] = e; // when done, add new entry
}
Aplicații cu tablouri: Scoreboard
● Ștergerea unui element de pe tabla de scoruri:
/** Remove and return the high score at index i. */
public GameEntry remove(int i) throws IndexOutOfBoundsException {
if (i < 0 || i >= numEntries)
throw new IndexOutOfBoundsException("Invalid index: " + i);
GameEntry temp = board[i]; // save the object to be removed
for (int j = i; j < numEntries - 1; j++) // count up from i (not down)
board[j] = board[j+1]; // move one cell to the left
board[numEntries-1] = null; // null out the old last score
numEntries--;
return temp; // return the removed object
}
Structuri secvențiale: Liste înlănțuite
● Listele înlănțuite sunt alternative la structurile secvențiale bazate pe tablouri.
○ elementele gestionate sunt încapsulate în noduri care păstrează legături cu nodurile
adiacente.
● Tipuri de liste înlănțuite (Linked Lists):
○ Simple: Singly Linked List
○ Circulare: Circularly Linked Lists
○ Duble: Doubly Linked Lists
Liste înlănțuite simple
● Lista înlănțuită simplu se bazează pe o “colaborare” între mai multe obiecte:
○ Fiecare nod păstrează
■ referința elementului gestionat;
■ referința către următorul nod.
○ Lista însăși păstrează
■ referința primului nod: head;
■ referința ultimului nod: tail
● nodul tail păstrează null pentru referința următorului nod.
● Structuri/clase de implementare
○ Clasa Node<E>
○ Clasa SinglyLinkedList<E>
Liste înlănțuite simple
● Gestionarea elementelor și referințele inter-noduri (clasa internă Node
reprezintă/abstractizează apartenența unui element-valoare la structura List):
private static class Node<E> {
/** The element stored at this node */
private E element; // an element stored at this node
/** A reference to the subsequent node in the list */
private Node<E> next; // a reference to the subsequent node in the list
public Node(E e, Node<E> n) {
element = e;
next = n;
}
public E getElement() { return element; }
public Node<E> getNext() { return next; }
public void setNext(Node<E> n) { next = n; }
}
Liste înlănțuite simple
● Declarația listei (ADT List) [extras (Goodrich14)]:
public class SinglyLinkedList<E> {
/** The head node of the list */
private Node<E> head = null; // head node of the list (or null if empty)
/** The last node of the list */
private Node<E> tail = null; // last node of the list (or null if empty)
/** Number of nodes in the list */
private int size = 0; // number of nodes in the list
/** Constructs an initially empty list. */
public SinglyLinkedList() { } // constructs an initially empty list
public int size() { return size; }
public boolean isEmpty() { return size == 0; }

}
Liste înlănțuite simple
● Stocarea elementelor în listă: adăugare:
public class SinglyLinkedList<E> {
public void addFirst(E e) { // adds element e to the front of the list
head = new Node<>(e, head); // create and link a new node
if (size == 0)
tail = head; // special case: new node becomes tail also
size++;
}
public void addLast(E e) { // adds element e to the end of the list
Node<E> newest = new Node<>(e, null); // node will eventually be the tail
if (isEmpty())
head = newest; // special case: previously empty list
else
tail.setNext(newest); // new node after existing tail
tail = newest; // new node becomes the tail
size++;
}
}
Liste înlănțuite simple
● Stocarea elementelor în listă: ștergere
public class SinglyLinkedList<E> {
public E removeFirst() { // removes and returns the first element
if (isEmpty()) return null; // nothing to remove
E answer = head.getElement();
head = head.getNext(); // will become null if list had only one node
size--;
if (size == 0)
tail = null; // special case as list is now empty
return answer;
}
}
Liste înlănțuite circulare
● Lista înlănțuită circular reprezintă la bază o listă înlănțuită simplu în care:
○ Lista însăși_
■ păstrează referința ultimului nod tail, care punctează către primul nod (head);
■ furnizează operația rotate() care facilitează mutarea primului element la capătul listei.
○ Nodul tail păstrează referința-head ca referință a următorului nod.
● Structuri/clase de implementare
○ Clasa Node<E>
○ Clasa CircularlyLinkedList<E>
Liste înlănțuite circular
● Declarația listei (TAD List) [extras (Goodrich14)]:
public class CircularlyLinkedList<E> {
/** The last node of the list */
private Node<E> tail = null; // we store tail (but not head)
/** Number of nodes in the list */
private int size = 0; // number of nodes in the list
/** Constructs an initially empty list. */
public CircularlyLinkedList() { } // constructs an initially empty list
public int size() { return size; }
public boolean isEmpty() { return size == 0; }
public E first() { // returns (but does not remove) the first element
if (isEmpty()) return null; // the head is *after* the tail
return tail.getNext().getElement(); }
public E last() { // returns (but does not remove) the last element
if (isEmpty()) return null;
return tail.getElement(); }
}
Liste înlănțuite circular
● Stocarea elementelor în listă: rotația

public class CircularlyLinkedList<E> {


...
/**
* Rotate the first element to the back of the list.
*/
public void rotate() { // rotate the first element to the back of the list
if (tail != null) // if empty, do nothing
tail = tail.getNext(); // the old head becomes the new tail
}
...
}
Liste înlănțuite dublu
● Lista înlănțuită dublu presupune că:
○ Fiecare nod păstrează_
■ referința elementului gestionat;
■ referința către nodul precedent;
■ referința către următorul nod;
○ Lista însăși păstrează referințele nodurilor “santinele”:
■ nodul de început: header;
● nodul header păstrează null pentru referința nodului precedent.
■ nodul sfârșit: trailer
● nodul trailer păstrează null pentru referința următorului nod.
● Structuri/clase de implementare
○ Clasa Node<E>
○ Clasa DoublyLinkedList<E>
Liste înlănțuite dublu
● Gestionarea elementelor și referințele inter-noduri [extras (Goodrich14)]:
private static class Node<E> {
/** The element stored at this node */
private E element; // reference to the element stored at this node
/** A reference to the preceding node in the list */
private Node<E> prev; // reference to the previous node in the list
/** A reference to the subsequent node in the list */
private Node<E> next;
public Node(E e, Node<E> p, Node<E> n) {
element = e; prev = p; next = n;
}
public E getElement() { return element; }
public Node<E> getPrev() { return prev; } public void setPrev(Node<E> p) { prev = p; }
public Node<E> getNext() { return next; } public void setNext(Node<E> n) { next = n; }
}
Liste înlănțuite dublu
● Declarația listei (ADT List) [extras (Goodrich14)]:
public class DoublyLinkedList<E> {
/** The head node of the list */
/** Sentinel node at the beginning of the list */
private Node<E> header; // header sentinel
/** Sentinel node at the end of the list */
private Node<E> trailer; // trailer sentinel
/** Number of elements in the list (not including sentinels) */
private int size = 0; // number of elements in the list
/** Constructs an initially empty list. */
/** Constructs a new empty list. */
public DoublyLinkedList() {
header = new Node<>(null, null, null); // create header
trailer = new Node<>(null, header, null); // trailer is preceded by header
header.setNext(trailer); // header is followed by trailer
}

}
Liste înlănțuite dublu
● Stocarea elementelor în listă: adăugare:
public class DoublyLinkedList<E> implements Cloneable {
public void addFirst(E e) {
addBetween(e, header, header.getNext()); // place just after the header
}
public void addLast(E e) {
addBetween(e, trailer.getPrev(), trailer); // place just before the trailer
}
private void addBetween(E e, Node<E> predecessor, Node<E> successor) {
// create and link a new node
Node<E> newest = new Node<>(e, predecessor, successor);
predecessor.setNext(newest);
successor.setPrev(newest);
size++;
}
...
}
2. Liste cu iteratori
● Liste indexate bazate tablouri
○ Tipul abstract List-ă (interfața List)
○ Implementare bazată pe tablouri
● Liste poziționale
○ Tipul abstract PositionalList
○ Implementare bazată pe liste (dublu) înlănțuite - Double Linked List
● Liste iterative
○ Interfața Iterable
○ Implementare iteratori
■ bazată pe tablouri
■ bazată pe liste (dublu) înlănțuite
Tipul abstract List(ă)
● Lista = secvență liniară de elemente.
○ Într-o secvență elementele sunt gestionate/localizate pe baza unui index Integer, asemănător
indecșilor asociați elementelor unui tablou.

Nume operație Descriere

size() Returnează numărul de elemente din listă.

isEmpty() Returnează un boolean care arată dacă există elemente.

get(i) Returnează elementul cu indexul i.

set(i,e) Înlocuiește elementul având indexul i cu e .

add(i,e) Adaugă un element pe poziția i (mută toate celelalte elemente cu indexul > i cu o
poziție).

remove(i) Îndepărtează din listă elementul cu indexul i.


Tipul abstract List(ă)
● Declarația TAD List<E>

public interface List<E> {


int size();
boolean isEmpty();
E get(int i) throws IndexOutOfBoundsException;
E set(int i, E e) throws IndexOutOfBoundsException;
void add(int i, E e) throws IndexOutOfBoundsException;
E remove(int i) throws IndexOutOfBoundsException;
}
TAD List: implementare ArrayList
● Implementare bazată pe un tablou: ArrayList, structura internă:
[extras (Goodrich14)]
public class ArrayList<E> implements List<E> {
// instance variables
/** Default array capacity. */
public static final int CAPACITY=16; // default array capacity
/** Generic array used for storage of list elements. */
private E[] data; // generic array used for storage
/** Current number of elements in the list. */
private int size = 0; // current number of elements
// constructors
/** Creates an array list with default initial capacity. */
public ArrayList() { this(CAPACITY); } // constructs list with default capacity
/** Creates an array list with given initial capacity. */
@SuppressWarnings({"unchecked"})
public ArrayList(int capacity) { // constructs list with given capacity
data = (E[]) new Object[capacity]; // safe cast; compiler may give warning
}
}
ArrayList Type Diagram (UML)
TAD List: implementare ArrayList
● Implementare bazată pe un tablou fix: ArrayList

public class ArrayList<E> implements List<E> {


public void add(int i, E e) throws IndexOutOfBoundsException {
checkIndex(i, size + 1);
if (size == data.length) // not enough capacity
throw new IllegalStateException("Array is full");
for (int k=size−1; k >= i; k−−) // start by shifting rightmost
data[k+1] = data[k];
data[i] = e; // ready to place the new element
size++;
}
}
TAD List: implementare dinamică add(i,e)
protected void resize(int capacity){
● Implementare bazată pe un tablou dinamic E[] temp =
(E[]) new Object[capacity];
for (int k=0; k < size; k++)
public class ArrayList<E> implements List<E> { temp[k] = data[k];
public void add(int i, E e) throws IndexOutOfBoundsException { data = temp;
checkIndex(i, size + 1); }
if (size == data.length) // not enough capacity
resize(2 * data.length); // so double the current capacity
for (int k=size-1; k >= i; k--) // start by shifting rightmost
data[k+1] = data[k];
data[i] = e; // ready to place the new element
size++;
}
}
Liste poziționale
● Indecșii nu reprezintă o abstractizare (întotdeauna) satisfăcătoare pentru
poziționarea unui element în cadrul unei secvențe.
● O listă pozițională:
○ introduce conceptul de poziție, independent de conceptul de indexare, specific
tablourilor;
○ poziția se comportă ca un marcator care nu va depinde de mecanismul intern de
stocare a elementului vizat, ci va abstractiza apartenența la listă și localizarea
relativ la elementele învecinate din secvența listei (ceea ce favorizează
implementarea cu structuri secvențiale de tip LinkedList).
LinkedPositionalList
Type Diagram (UML)
Liste poziționale: tipul abstract Position<E>
● Tipul abstract pentru poziție poate fi definit simplu prin interfața:

public interface Position<E> {


/**
* Returns the element stored at this position.
*/
E getElement() throws IllegalStateException;
}
Liste poziționale: TAD PositionalList<E>
● Tipul abstract al listei poziționale introduce un set specific de operații de
localizare/poziționare în cadrul secvenței de elemente:
Nume operație Descriere

first() Returnează poziția primului element din listă.

last() Returnează poziția ultimului element din listă.

before(p) Returnează poziția dinaintea poziției p.

after(p) Returnează poziția următoare poziției p.

isEmpty() Returnează un boolean care arată dacă există elemente.

size() Returnează numărul de elemente din listă.


Liste poziționale: TAD PositionalList<E>
● Structură de control pentru parcurgerea unei liste:

Position<String> cursor = lst.first( );


while (cursor != null) {
System.out.println(cursor.getElement( ));
cursor = lst.after(cursor); // advance to the next position (if any)
}
Liste poziționale: TAD PositionalList<E>
● Tipul abstract al listei poziționale introduce un set specific de operații de
actualizare a secvenței de elemente:
Nume operație Descriere

addFirst(e) Inserează e ca prim element din listă.

addLast(e) Inserează e ca ultim element din listă.

addBefore(p, e) Inserează e pe poziția dinaintea poziției p.

addAfter(p, e) Inserează e pe poziția următoare poziției p.

set(p,e) Înlocuiește elementul de pe poziția p cu e.

remove(p) Îndepărtează (și returnează) elementul de pe poziția p, invalidând poziția.


Liste poziționale: TAD PositionalList<E>
● Tipul abstract pentru poziție poate fi definit prin interfața [extras (Goodrich14)]:
public interface PositionalList<E> {
int size();
boolean isEmpty();
Position<E> first();
Position<E> last();
Position<E> before(Position<E> p) throws IllegalArgumentException;
Position<E> after(Position<E> p) throws IllegalArgumentException;
Position<E> addFirst(E e);
Position<E> addLast(E e);
Position<E> addBefore(Position<E> p, E e) throws IllegalArgumentException;
Position<E> addAfter(Position<E> p, E e) throws IllegalArgumentException;
E set(Position<E> p, E e) throws IllegalArgumentException;
E remove(Position<E> p) throws IllegalArgumentException;
}
Liste poziționale: Implementare Position<E>
● Implementare prin clasa internă Node<E>, structura internă
[extras (Goodrich14)]:
class Node<E> implements Position<E> {
/** The element stored at this node */
private E element; // reference to the element stored at this node
/** A reference to the preceding node in the list */
private Node<E> prev; // reference to the previous node in the list
/** A reference to the subsequent node in the list */
private Node<E> next; // reference to the subsequent node in the list

public E getElement() throws IllegalStateException {


if (next == null) // convention for defunct node
throw new IllegalStateException("Position no longer valid");
return element;
}
public Node<E> getPrev() {...} public Node<E> getNext() {...}
public void setPrev(Node<E> p) {...} public void setNext(Node<E> n) {...}
}
Liste poziționale: Implementare PositionalList<E>
● Implementare ca listă dublu înlănțuită Doubly Linked List, structura internă
[extras (Goodrich14)]:
public class LinkedPositionalList<E> implements PositionalList<E> {
// instance variables of the LinkedPositionalList
/** Sentinel node at the beginning of the list */
private Node<E> header; // header sentinel

/** Sentinel node at the end of the list */


private Node<E> trailer; // trailer sentinel

/** Number of elements in the list (not including sentinels) */


private int size = 0; // number of elements in the list

... ...
}
Iteratori
● Un iterator reprezintă un șablon de proiectare (design pattern) care abstractizează
procesul de scanare/parcurgere a unei secvențe de elemente, element cu element.
● Un TAD pentru definirea unui iterator trebuie să conțină cel puțin operațiile:
○ hasNext() prin care se verifică dacă mai este cel puțin un element în secvență;
○ next() care va return următorul element din secvență.
● Parcurgerea unei liste de elemente - șiruri de caractere folosind un iterator:
while (iter.hasNext( )) {
String value = iter.next( );
System.out.println(value);
}
Interfața Iterable
● Iteratorul trebuie furnizat de liste prin operația iterator() - tipul abstract List
extinde interfața/tipul abstract Iterable:

public interface Iterable<T> {


Iterator<T> iterator();
}

public interface List<E> extends Iterable<E> {


Iterator<E> iterator();
}

public interface PositionalList<E> extends Iterable<E> {


Iterator<E> iterator();
}
Implementare Iterator<E>: ArrayIterator
● Declarare Iterator prin tablou intern al clasei ArrayList:

public class ArrayList<E> implements List<E> {


private class ArrayIterator implements Iterator<E> {...}
public Iterator<E> iterator() {
return new ArrayIterator();// create a new instance of the inner class
}
}
Implementare Iterator<E>: ArrayIterator
● Implementare Iterator pentru un ArrayList:
[extras (Goodrich14)]
class ArrayIterator implements Iterator<E> {
/** Index of the next element to report. */
private int j = 0; // index of the next element to report
private boolean removable = false; // can remove be called at this time?
public boolean hasNext() { return j < size; } // size is field of outer instance
public E next() throws NoSuchElementException {
if (j == size) throw new NoSuchElementException("No next element");
removable = true; // this element can subsequently be removed
return data[j++]; // post-increment j, so it is ready for future call to next
}
public void remove() throws IllegalStateException {
if (!removable) throw new IllegalStateException("nothing to remove");
ArrayList.this.remove(j-1); // that was the last one returned
j--; // next element has shifted one cell to the left
removable = false; // do not allow remove again until next is called
}
}
Utilizare iterator: iterații for-each
Iterator<ElementType> iter = collection.iterator( );
while (iter.hasNext( )) {
ElementType variable = iter.next( );
loopBody // may refer to ”variable”
}

for (ElementType variable : collection) {


loopBody // may refer to ”variable”
}
Iterator pozițional: Iterator<Position<E>>
● Implementare Iterator pozițional (pentru o structură PositionalList):
[extras (Goodrich14)]
class PositionIterator implements Iterator<Position<E>> {
/** A Position of the containing list, initialized to the first position. */
private Position<E> cursor = first(); // position of the next element to report
/** A Position of the most recent element reported (if any). */
private Position<E> recent = null; // position of last reported element
public boolean hasNext() { return (cursor != null); }
public Position<E> next() throws NoSuchElementException {
if (cursor == null) throw new NoSuchElementException("nothing left");
recent = cursor; // element at this position might later be removed
cursor = after(cursor);
return recent;
}
public void remove() throws IllegalStateException {
if (recent == null) throw new IllegalStateException("nothing to remove");
LinkedPositionalList.this.remove(recent); // remove from outer list
recent = null; // do not allow remove again until next is called
}
}
Iterator elementar: Implementare Iterator<E>
● Implementare Iterator elementar (pentru o structură PositionalList), metode:

private class ElementIterator implements Iterator<E> {


Iterator<Position<E>> posIterator = new PositionIterator();
public boolean hasNext() { return posIterator.hasNext(); }
public E next() { return posIterator.next().getElement(); } // return element!
public void remove() { posIterator.remove(); }
}
Utilizare iterator pozițional

// invocare iterator ElementIterator<String>


for (String guest : lst){
...
}

// invocare iterator PositionIterator<String>


for (Position<String> p : lst.positions( )){
...
}
Studiu de caz: Aplicația ScoreBoard cu ArrayList
● Structura internă clasa IterativeListScoreboard:
private List<GameEntry> board; private int capacity;
● Adăugarea unei noi intrări pe tabela de scor:
public void add(GameEntry e) {
// board will add its first element (is empty)
if (board.isEmpty()) { board.add(0, e); return;}
int newScore = e.getScore();
// is the new entry e really a high score?
if (this.board.size() < this.capacity ||
newScore > board.get(this.board.size() - 1).getScore()) {
Iterator<GameEntry> iterator = board.iterator();
int j = 0;
while(iterator.hasNext() && iterator.next().getScore() > newScore)
j++;
this.board.add(j, e);
}
// check capacity
if (this.board.size() > this.capacity)
this.board.remove(this.board.size() - 1);
}
Studiu de caz: Aplicația ScoreBoard cu PositionalList
● Structurila internă clasa PositionalListScoreboard:
private PositionalList<GameEntry> board; private int capacity;
● Adăugarea unei noi intrări pe tabela de scor:
public void add(GameEntry e) {
int newScore = e.getScore();
// board will add its first element (is empty)
if (board.isEmpty()) { board.addFirst(e); return;}
// is the new entry e really a high score?
if (board.size() < this.capacity || newScore > board.last().getElement().getScore()) {
// start with last position and process backwards
Position<GameEntry> position = board.last();
while(position!=null && position.getElement().getScore() < newScore) {
// previous position to process next
position = board.before(position);
}
if (position != null) board.addAfter(position, e);
else board.addFirst(e);
// check capacity
if (this.board.size() > this.capacity) this.board.remove(board.last());
}
}
Exemple Laborator
● Studiu de caz complet: ScoreBoard cu PositionalList
○ Completare metoda GameEntry remove(int i);
● Studiu de caz complet: ScoreBoard cu ArrayList
○ Completare metoda GameEntry remove(int i);
Bibliografie
● Michael T. Goodrich, Roberto Tamassia, Michael H. Goldwasser, Data
Structures and Algorithms in Java™, Sixth Edition, Wiley, 2014 [Goodrich14]
● Robert Sedgewick, Kevin Wayne, Algorithms, Fourth Edition,
Addison-Wesley, 2011 [Sedgewick11]
Referințe

2014_Data Structures and Algorithms in Java 2011_Sedgewick_Algorithms(Sedgewick11)


(Goodrich14)
● Chapter 3: Fundamental Data Structures, p103 ● C1.2 Data Abstraction (p.64)
○ 3.1 Using Arrays: 3.1.1, 3.1.5 ● C1.3 Bags, Queues, Stacks(p.120)
○ 3.2 Singly Linked List
○ 3.4 Doubly Linked List
● Chapter 7: List and Iterator ADTs, p257
○ 7.1 The List ADT
○ 7.2 Array Lists
○ 7.4 Iterators

S-ar putea să vă placă și