Download Data Structures I Lab (3)

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Document related concepts

Array data structure wikipedia, lookup

Linked list wikipedia, lookup

Transcript
Data Structures I Lab (3)
CSS 162 : Programming Methodology
Autumn 2012, Instructor Rob Nash
Summary
The purpose of this lab is to practice what we’ve covered in class and in the readings (Chapter 6,15) by
building a stack, queue, and a list.
Data Structure Background
A Data Structure is a composite data storage tool that organizes elements of a set and offers operations
over those elements in the set. Frequently called a structure, class or set, these tools are used to
provide order and operations to a collection of elements. Data structures vary in how they are built
internally, how they organize data (sorted or unsorted, for example), and the operations provided.
Frequently these operations are compared to one another with respect to efficiency using a notation we
will cover shortly in class, called ”Big Oh” notation. One structure that is useful for quick searches (say
for an airlines company searching for connections) may have disadvantages in other areas, such as in
memory consumed – or trade one fast operation that will be used frequently for a slow operation that
will be rarely used.
Static Data Structures
If your data structure’s size is declared at compile-time, you are a static structure in the sense that you
cannot grow or shrink at runtime depending on the applications needs. These are implemented on top
of arrays, which are mapped contiguously in memory for fast (or constant, meaning a Big-O(1)) access to
any element. Using arrays to build more complex data structures serves as a great introduction to the
behaviors and mechanics of Stacks, Queues, and (more generally) Lists.
Dynamic Data Structures
These structures can allocate and de-allocate memory at runtime depending on the requirements of the
client application. These are dynamic structures in that their memory footprint may change over the
duration of the program’s execution. To build such structures, it would be a needless limitation to
impose contiguous storage, requiring n back-to-back blocks of memory to hold a list of n items. Thus
the total memory required may be available, but if we insist on a linear mapping we may be unable to
use the memory, even if available, due to fragmentation (what about coalescing holes?). Our dynamic
structures will instead allocate only the memory they need wherever there is RAM available, and we will
“stitch together” lists from these individual elements or nodes.
Getting Started
Start by downloading the driver code and executing it. Note that the code compiles and runs as is, even
though we have yet to make any data structures. This is because the driver is using Java’s preexisting
library of Data Structures (which is expansive). Once you have this driver up and running, we’ll replace
one data structure at a time with one you’ve built and rerun the tests looking for the same behavior we
observed when using Java’s predefined data structures.
Building an Array-Based Stack Class (LIFO)
Create a new class called ArrayStack and define two data members for use in managing this stack. In
this example, we’ll build a stack of Strings, so your array will be of type String and your count an integer.







Create a new class called ArrayStack.
Declare an array for your Strings and an integer for your size
public void push(String next)
o This pushes the next element onto the top of the stack
public String pop()
o This returns the top element on the stack and decrements the size variable
public boolean isEmpty()
o Determines if the size is zero
Go to the driver software and uncomment out the Stack driver portion, leaving the other tests
commented out.
o Compile and run your software with the driver
o Test your Stack – does it reverse the order of elements when pushed and popped?
Change the type of element your stack will hold from String to Object
o You’ll have to change the type in the push() and pop() methods, too.
o Did your code have errors upon making this change?
 Why not?
 How is this related to inheritance?
Building an Array-Based Queue (FIFO)
Start by creating a new class named ArrayQueue, and copying-and-pasting over the class we just
completed (ArrayStack) above. Note that, with Inheritance, we could avoid this extra copying.


Create a new class called ArrayQueue.
Copy the code from ArrayStack to ArrayQueue.



Change the methods push() and pop() to enqueue() and dequeue()
Modify the dequeue method so that instead of returning the last element in the array it
accomplishes the following:
a. You return the first element in the array (FIFO instead of LIFO)
b. You shift all the elements in the array over to the left by one, effectively overwriting
the first element in the array (and as a side-effect, duplicating the last element)
c. Decrement the count by 1.
Test your code with the provided Queue driver.
d. Does it print the sentence out in correct order, or reverse the words?
Array-Based List
A List is more flexible than the Stack and Queue in that you can add or remove an item at any location in
the list (as opposed to inserts and removes only at the ends of the list). When we have a List structure
at our disposal, it’s easy to build stacks and queues on top of the list by restricting where elements are
inserted and removed. Using inheritance, you can quickly reuse your List code in your Stack and Queue
classes. Start by creating a new class, and copying over the code from an existing class such as
ArrayQueue.
(1)
(2)
(3)
(4)
Create a new class called ArrayList
Copy the code from ArrayStack or ArrayQueue to ArrayList
Change the methods from push() and pop() to insert(int idx) and remove(int idx)
Modify the insert(int idx) method so that it will:
a. Make room in your array by shifting all elements over starting at index idx and
ending at count
b. Put the new data item at data[idx]
c. Add one to your count (see the diagram below to conceptualize this)
i
B
t
Notice how we shift
one element beyond
the existing size, to
make room for the
newly inserted
element.
Insert at 1
B
i
i
t
Overwrite the
old value with
the new
B
a
t
i
(5) Modify the remove(int idx) method so that it will:
a. Overwrite the element at idx with the element at idx+1, all the way to the end of
your array (size – 1).
b. Decrement your count by one.
(6) Test your List code using the provided driver.
Delete index 1
B
a
i
t
B
i
t
t
Decrement size so this is the
last element
A Linked List Implementation of a Stack
Now that we’re familiar with the array-based versions of the Stack and Queue, we will create a new
version of Stack using a different implementation. We will build a structure that functions externally just
like our array-based stack we built earlier, but differs internally with respect to how we accomplish
these behaviors. You start by copying and pasting your code from the Stack Class we built earlier.
Then, remove the code inside each method, and remove the array and count data members. You will
need only one data member here: a pointer to the beginning, head, or start of your list. This will point
to the first Node object in the list, or null if the list is empty.
(1)
(2)
(3)
(4)
Copy your existing Stack implementation to a new class (LinkedListStack)
Jump ahead to the next section and build the Node class below
Remove the old data members and insert the Node member that starts your list.
Modify the implementations of add/remove (or push/pop) to use Nodes. The following
code snippets may be useful to you here.
1. Node current = start;
2. while(current.next != null) { //or current != null
3. current = current.next;
(5) Test your Linked List Stack with the provided driver.
The Node Class
Declare a class that will hold two data items; one to populate the actual value(s) in the list, and the other
to reference the next element in our list. This class will be quite small (2 data members and one
constructor), and will usually be declared internally to the List, Stack, or Queue that uses it; this is called
tight coupling, and we usually seek to avoid this (why?).
(1) Build a new private inner class to your Stack class called Node.
(2) Add the two data members inside of Node
a. int data; //if we’re storing integers
b. Node next; //our “next” pointer, null if we’re at the end of our list
(3) Build a constructor used to initialize each of the fields in the Node.
a. public Node(int d, Node n);
Outcomes
If you can build one class, you can build a second more quickly by reusing the software you’ve already
built. In this lab, we reuse this software by copying and pasting previous class code into new classes.
This is one method for reuse, but it has several drawbacks. We will look next at inheritance whereby a
new class can be derived from an existing class by extending the parent class and creating a child class
that effectively “borrows” all of the data and methods of the parent class, in addition to introducing its
own methods. You could then build a single, general List class which provides arbitrary inserts and
removes at any point in the list, and then quickly build a Stack or a Queue by inheriting from the List
class and modifying (overriding) the insert and remove methods as appropriate. This is the goal of your
next assignment, which will be discussed further in class.