490 likes | 649 Views
Chapter 2 Foundational Data Structures. Outline. Arrays Extending Java Arrays Constructors Assign Method Accessor Methods Array Indexing Methods – get and put Resizing an Array – setBase and setLength Multi-Dimensional Arrays Array Subscript Calculations An Implementation Constructor
E N D
Chapter 2Foundational Data Structures ICS 202 2011 spring Data Structures and Algorithms
Outline • Arrays • Extending Java Arrays • Constructors • Assign Method • Accessor Methods • Array Indexing Methods – get and put • Resizing an Array – setBase and setLength • Multi-Dimensional Arrays • Array Subscript Calculations • An Implementation • Constructor • Array Indexing Methods – get and put • Matrices • Dense Matrices • Canonical Matrix Multiplication • Singly-Linked Lists • An Implementation • LinkedList Constructor • purage Method • Accessor Methods • getFirst and getLAst Methods • prepend Method • append Method • assign Method • extract Method • insertAfter and insertBefore Methods
Abstract Data Types (ADTs) include stacks, queues, ordered lists, sorted lists, hash and scatter tables, trees, priority queues, sets, and graphs. • This chapter introduces the concept of Arrays and Linked list • They are called Foundational Data Structure (they are the base on which almost all of the ADTs are built)
int [ ] a = new int [5] • Allocates an array of five integers and assigns it to the variable a 1. Arrays • An array is an object that contains a collection of objects, all of the same type. • The elements of an array are accessed using integer indxes. • The first element of an array has always index zero • All array objects in Java have an int field called length. • Array-name.length returns the number of elements of an array
1. Arrays • Java checks at run time that the index used in every array access is valid (valid indices are between 0 and length - 1). • If an invalid index expression is used, an IndexOutOfBoundsException exception is shown. • Once allocated, the size of a java array object is fixed. • The elements of an array occupy consecutive memory locations. • The total storage required to represent an array can be estimated • Let S(n) be the total storage (memory) needed to represent an array of n ints: S(n) sizeof(int[n]) (n+1)sizeof(int)
int [6] int 6 length int int int int int int 3 1 4 1 5 9 1. Arrays Memory representation of java arrays
Solution 4.1 1publicclass Array 2 { 3protectedObject [ ] data ; // array of Java objects 4protectedint base ; // the lower bound for array index 5 6 // … 7 } 1. Arrays: Extending Java arrays • Some shortcomings of java arrays • Indexes range from zero to n-1 (n is the array length) • The size is fixed once it is allocated.
1. Arrays: Constructors 4.2 publicclass Array { protectedObject [ ] data ; // array of Java objects protectedint base ; // the lower bound for array index public Array (int n, int m) { data = newObject [n]; // allocation of an array of n Objects base = m; } public Array ( ) { this (0, 0); // n = 0 and m = 0 } public Array ( ) { this (n, 0); // m = 0 } }
1. Arrays: assign Method 4.3 publicclass Array { protectedObject [ ] data ; // array of Java objects protectedint base ; // the lower bound for array index publicvoid assign (Array array) { if (array != this) { if (data.length != array.data.length) data = newObject [array.data.length] ; for (int i =0; i < data.length; ++i) data [i] = array.data[i] ; base = array.base; } } }
1. Arrays: assign Method • The assign method provides a way to assign the elements of one array to another • It is intended to be used like this: Array a = new Array (5); Array b = new Array (5); // … b.assign (a) ; // assign the elements of a to b
1. Arrays: Accessor Methods 4.4 publicclass Array { protectedObject [ ] data ; // array of Java objects protectedint base ; // the lower bound for array index publicObject [ ] getData ( ) { return data; } publicint getBase ( ) { return base; } publicint getLength ( ) { return data.length; } // these three methods are used to inspect the contents of the array }
The elements of a Java array are accessed by enclosing the index expression between brackets [ ]. a[2] = b[3]; • When using the Array class, we can access its elements like this: a.getData( )[2] = b.getData( )[3]; • Unfortunately, the syntax in this case is ugly. We can however, define methods for indexing an array like this: a.Put (2, b.get (3)); 1. Arrays: Array Indexing Methods: get and put
1. Arrays: Array Indexing Methods: get and put 4.5 publicclass Array { protectedObject [ ] data ; // array of Java objects protectedint base ; // the lower bound for array index publicObject get (int position) { return data [position - base]; // takes an index position, and returns the element found in the // array at that given position } publicvoid put (int position, Object object) { data [position - base] = object ; // takes an index and an Object and stores the object in the array // at the given position } }
1. Arrays: Resizing an Array: setBase and setLength 4.6 publicclass Array { protectedObject [ ] data ; // array of Java objects protectedint base ; // the lower bound for array indices publicvoid setBase (int base) { this.base = base; // modifies the base field } publicvoid setLength (int newLength) { if (data.length != newLength) { Object [ ] newData = newObject [newLength] ;// create array newdata of type object with newlength int min = data.length < newLength ? ; // ternary operator to assign data.length : newLength; // minimum(data.length ,newLength) to min for (int i = 0; i < min; ++i) newData [i] = data[i]; // copies the old array elements to the new array data = newData; } } }
x[i] selects the ith one-dimensional array x[i][j] selects the jth element from that array 2. Multi-Dimensional Arrays • The Java does not really support multi-dimensional arrays. • In Java, a two-dimensional array x is really an array of one-dimensional arrays int [ ][ ] x = newint [3][5]; • The multi-dimensional arrays have the same things of simple one-dimensional arrays ( Indices range from zero to length-1 for each dimension, no array assignment operator, the number of dimensions and the size of each dimension are fixed once the array has been allocated).
2. Multi-Dimensional Arrays: Array Subscript Calculations • The memory of a computer is essentially a one-dimensional array • A natural way to implement a multi-dimensional array is to store its elements in a one-dimensional array. • We need a mapping function to switch from multi-dimensional array indices into one-dimensional array index. Given an element a[i][j] which element b[k] it corresponds? We need a mapping function f such that k = f(i, j) int [ ] [ ] a = newint [2][3]; int [ ] b = newint [6];
Position Value b[0] a[0][0] row 0 b[1] a[0][1] b[2] a[0][2] int [ ] [ ] a = newint [2][3]; b[3] a[1][0] b[4] a[1][1] row 1 b[5] a[1][2] 2. Multi-Dimensional Arrays: Array Subscript Calculations • The mapping function determines the way in which the elements of a multi-dimensional array are sorted in memory. • The most common way to represent an array is in row-major order.
Then the position of the element is given by Where 2. Multi-Dimensional Arrays: Array Subscript Calculations • Suppose we have an nD array a with dimensions:
publicclass MultiDimensionalArray { int [ ] dimensions ; // n dimensions int factors ; // n elements the jth element = fj Object [ ] data ; // used to hold the elements of the multi-dimensional // array in row-major order. // … } 2. Multi-Dimensional Arrays: An implementation • In this section we illustrate the implementation of a multi-dimensional array using a one-dimensional array.
2. Multi-Dimensional Arrays: Constructor publicclass MultiDimensionalArray { int [ ] dimensions ; // n dimensions int factors ; // n elements the jth element = fj Object [ ] data ; // used to hold the elements of the multi-dimensional array public MultiDimensionalArray (int [ ] arg) { dimensions = new int [arg.length]; factors =new int [arg.length]; int product =1; for (int i = arg.length-1; i>=0; --i) { dimensions [i] = arg[i]; factors[i] = product; product * = dimensions[i]; } data = newObject [product]; } }
2. Multi-Dimensional Arrays: An implementation • To create a 357 three-dimensional array, we invoke the constructor like this. MultiDimensionalArray a = new MultiDimensionalArray (new int [ ]{3, 5, 7}); • The constructor copies the dimensions of the array into the dimensions array, and then it computes the factors array. • The constructor then allocates a one-dimensional array of length m given by:
2. Multi-Dimensional Arrays: Array Indexing Methods – get and put • The elements of a multi-dimensional array are indexed using the get and put methods. We can access the (i, j, k)th element of a three-dimensional array a: a.get (newint [ ] {i, j, k}); • We can modify the (i, j, k)th element like • a.put (newint [ ] {i, j, k}, value);
2. Multi-Dimensional Arrays: Array Indexing Methods – get and put publicclass MultiDimensionalArray { int [ ] dimensions ; // n dimensions int factors ; // n elements the jth element = fj Object [ ] data ; // used to hold the elements of the multi-dimensional array protected int getOffset (int [ ] indices) { if (indices.length != dimensions.length) throw new IllegalArgumentException(“wrong number of indices”); int offset =0; for (int i = 0; i < dimension.length; ++i) { if (indices [i] < 0 || indices [i] >= dimensions [i]); throw new IndexOutOfBoundsException( ); offset += factors [i] * indices [i]; } return offset; } // Continue the program in the next slide
2. Multi-Dimensional Arrays: Array Indexing Methods – get and put public Object get (int [ ] indices) { return data [getOffset (indices)] ; } public void put (int [ ] indices, Object object) { data [getOffset (indices)] = object; } }
2. Multi-Dimensional Arrays: Matrices • In this section we consider two dimensional matrices of doubles. Matrix interface { double get (int i, int j); // get an element void put (int i, int j, double d) // insert an element Matrix transpose (); Matrix times (Matrix matrix); Matrix plus (Matrix matrix); }
2. Multi-Dimensional Arrays: Dense Matrices • The simplest way to implement a matrix is to use an array of arrays public class DenseMatrix implements Matrix { protected int numberOfRows; protected int numberOfColumns; protected double [ ][ ]array; public DenseMatrix (int numberOfRows, int numberOfColumns) { this.numberOfRows = numberOfRows ; this.numberOfColumns = numberOfColumns ; array = newdouble [numberOfRows][numberOfColumns]; } }
2. Multi-Dimensional Arrays: Canonical Matrix Multiplication • Given an mn matrix A and an np matrix B, the product C = AB is an mp matrix. • The elements of the result matrix are given by: • To compute the product matrix C, we need to compute mp summations each of which is the sum of n product terms.
2. Multi-Dimensional Arrays: Canonical Matrix Multiplication public class DenseMatrix implements Matrix { protected int numberOfRows; protected int numberOfColumns; protected double [ ][ ]array; public Matrix times (Matrix mat) { DenseMatrix arg = (DenseMatrix) mat; if (numberOfColumns != arg.numberOfRows) throw new IllegalArgumentException (“incompatible matrices”); DenseMatrixresult = new DenseMatrix (numberOfRows, arg.numberOfColumns); for (int i = 0; i < arg.numberOfRows; ++i) { for (int j = 0; j < arg.numberOfColumns; ++j) { double sum = 0; for (int k = 0; k < numberOfColumns; ++k) sum+ = array [i][k] + arg.array [k][j]; result.array [i][j] = sum; } } return result; } }
(a) head (b) head tail (c) head Sentinel tail (d) 3. Singly-Linked Lists • The singly-linked list is the most basic of all the linked data structures. • A singly-linked list is simply a sequence of dynamically allocated objects, each of which refers to its successor in the list.
(a) head 3. Singly-Linked Lists • This type is the basic singly-linked list. • Each element of the list refers to its successor. • The last element contains the null reference • One variable, labeled head is used to keep track of the list. • This type of singly-linked list is inefficient if we want to add elements to the end of the list (we need to locate the last element).
(b) head tail 3. Singly-Linked Lists • A second variable tail is used to add elements to the tail easily.
(c) head Sentinel 3. Singly-Linked Lists • The sentinel element is never used to hold data • It is used to simplify the programming of certain operations (for example, the head variable is never modified by adding new elements) • This list is circular: the last element refers to the sentinel. • In that case insertion in the head, in the tail or in any position is the same operation.
tail (d) 3. Singly-Linked Lists • The variable tail refers to the last element of the list. • The last element refers to the first element • It is easy in this case to insert both at the head and at the tail of this list.
(a) head (c) head Sentinel head (b) tail tail (d) 3. Singly-Linked Lists • The empty singly-linked list for the four types described before are as following
Element Element Integer Integer datum datum 3 4 next next Element Integer datum 1 next 3. Singly-Linked Lists: An Implementation • We will implement the second type of singly-linked list. LinkedList head tail
3. Singly-Linked Lists: An Implementation public class LinkedList { protected Element head; protected Element tail; public final class Element // used to represent the elements of a linked list { Object datum; Element next; Element (Object datum, Element next) { this.datum = datum; this.next = next; ) public Object getDatum ( ) { return datum; } public Object getNext ( ) { return next; } } }
3. Singly-Linked Lists: LinkedList Constructor The code for the no-arg LinkedList constructor is: public class LinkedList { protected Element head; protected Element tail; public LinkedList ( ) { } // … } Since the fields head and tail are initially null, the list is empty by default.
3. Singly-Linked Lists : purge(clean)Method The purge method is used to discard the current list contents and to make the list empty again. public class LinkedList { protected Element head; protected Element tail; public void purge ( ) { head = null; tail = null; } // … }
3. Singly-Linked Lists: Accessor Methods public class LinkedList { protected Element head; protected Element tail; public Element getHead ( ) { return head ; } public Element getTail ( ) { return tail ; } public boolean isEmpty ( ) { return head == null ; // indicates whether the list is empty } // … }
3. Singly-Linked Lists: getFirst and getLast Methods public class LinkedList { protected Element head; protected Element tail; public Object getFirst ( ) { if (head == null) thrownew ContainerEmptyException (); return head.datum ; // returns the first element of the list } public Object getLast ( ) { if (tail == null) thrownew ContainerEmptyException (); return tail.datum ; ; // returns the last element of the list } }
3. Singly-Linked Lists: prepend Method public class LinkedList { protected Element head; protected Element tail; public void prepend (Object item) // insert an element in front of the first element of the list { Element tmp = new Element (item, head) ; if (head == null) tail = tmp; head = tmp ; // update the head to refer the new first element } //… }
3. Singly-Linked Lists: append Method public class LinkedList { protected Element head; protected Element tail; public void append (Object item) // insert an element at the tail of the list { // the new element becomes the new tail of the list Element tmp = new Element (item, null) ; // allocates a new element //the datum field is initialized with item and the next field is set to null if (head == null) // the list is empty head = tmp; else tail.next = tmp ; tail = tmp; // update the tail to refer the new last element } //… }
3. Singly-Linked Lists: assign Method public class LinkedList { protected Element head; protected Element tail; public void assign (LinkedList list) // assign the elements of a linked list { // to another list if (list != this) { purge(); // the new list must be empty for (Element ptr =list.head; ptr !=null; ptr = ptr.next) append (ptr.datum); // add an element at the tail of the new list } } //… }
3. Singly-Linked Lists: extract Method public class LinkedList { protected Element head; protected Element tail; public void extract (Object item) // to delete an element from the list { Element ptr = head; Element prevPtr = null; while (ptr != null && ptr.datum != item) // searches for the element to be deleted { prevPtr = ptr; ptr = ptr.next ; } if (ptr == null) // the element is not found throw new IllegalArgumentException (“item not found”); if (ptr == head) head = ptr.next; else prevPtr.next = ptr.next; if (ptr == tail) tail = prevPtr; }
3. Singly-Linked Lists: insertAfter and insertBefore Methods public class LinkedList { protected Element head; protected Element tail; public final class Element { Object datum ; Element next ; public void insertAfter (Object item) { next = new Element (item, next) ; if (tail == this) tail = next ; } public void insertBefore (Object item) { Element tmp = new Element (item, this) ; if (this == head) head = tmp ; else { Element prevPtr = head; while (prevPtr != null && prevPtr.next != this) prevPtr = prevPtr.next; prevPtr.next = tmp; } } } }