This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
haas:fall2015:data:projects:dls0 [2015/11/08 13:41] – [Errata] wedge | haas:fall2015:data:projects:dls0 [2015/11/16 15:55] (current) – [Errata] wedge | ||
---|---|---|---|
Line 11: | Line 11: | ||
This section will document any updates applied to the project since original release: | This section will document any updates applied to the project since original release: | ||
- | * __revision | + | * __revision |
+ | * on test 7, a copy of a populated stack, the unit test was incorrectly expecting " | ||
=====Objective===== | =====Objective===== | ||
- | In this project, resume our conceptual journey and explore another data structure: stacks. | + | In this project, |
- | + | ||
- | Also, update pertinent list library functions to conform to expanded specifications: | + | |
- | + | ||
- | * **qty** in list struct (see below): | + | |
- | * **mklist()** | + | |
- | * **insert()** | + | |
- | * **append()** | + | |
- | * **obtain()** | + | |
- | * additional modes for display (see below): | + | |
- | * **display()** | + | |
- | + | ||
- | It is recommended that you tend to the list enhancements before starting on the stack, as you'll need that functionality online in order to get a fully operational stack. | + | |
=====Background===== | =====Background===== | ||
A **stack** is considered one of the most important data structures, along with **queues** (next week's project) and trees. And it is largely because of how often we find them playing out in nature or our day-to-day lives. | A **stack** is considered one of the most important data structures, along with **queues** (next week's project) and trees. And it is largely because of how often we find them playing out in nature or our day-to-day lives. | ||
Line 68: | Line 57: | ||
The stack data structure presents certain advantages that encourages its use in solving problems (why do we stack a bunch of papers all in the same place to create piles? Why is that more advantageous than giving each one its own unique desk space?), and we accomplish that by its compositional definition: | The stack data structure presents certain advantages that encourages its use in solving problems (why do we stack a bunch of papers all in the same place to create piles? Why is that more advantageous than giving each one its own unique desk space?), and we accomplish that by its compositional definition: | ||
- | * a stack has a **top**, basically a node pointer that constantly points to the top node in the stack (equivalent to the underlying list' | + | * a stack has a **top**, basically a node pointer that constantly points to the top node in the stack (equivalent to the underlying list' |
- | * to put an item on the stack, we **push** it there. So one of the functions we'll be implementing is **push()**, which will take the node we wish to place on the given stack, and push will handle all the necessary coordination with its underlying list. | + | * to put an item on the stack, we **push** it there. So one of the functions we'll be implementing is **push()**, which will take the node we wish to place on the given stack, and push will handle all the necessary coordination with its underlying list (i.e. it should call existing list functions to manipulate the list) |
* to get an item off of the stack, we **pop** it. In our **pop()** function, we grab the **top** node off the stack (this also translates into a set of list-level transactions that our **pop()** function will handle for us). | * to get an item off of the stack, we **pop** it. In our **pop()** function, we grab the **top** node off the stack (this also translates into a set of list-level transactions that our **pop()** function will handle for us). | ||
Line 85: | Line 74: | ||
* **is the stack empty?**: the ability to query the stack and determine if it is empty or non-empty (or perhaps if non-empty, how full is it?) | * **is the stack empty?**: the ability to query the stack and determine if it is empty or non-empty (or perhaps if non-empty, how full is it?) | ||
- | While we may be implementing these supplemental functions, it should be noted that not only are they in no way necessary for using a stack, they could be detrimental (just as relying on **qty** in the sll projects was), as one could rely on them as a crutch. | + | While we may be implementing these supplemental functions, it should be noted that not only are they in no way necessary for using a stack, they could be detrimental (just as relying on counting can be a crutch). |
Their inclusion should ONLY be viewed as a means of convenience (in certain scenarios they may result in less code needing to be written), but NOT as something you should routinely make use of. | Their inclusion should ONLY be viewed as a means of convenience (in certain scenarios they may result in less code needing to be written), but NOT as something you should routinely make use of. | ||
====size can matter==== | ====size can matter==== | ||
- | With a stack, there sometimes exists a need to cap its total size (especially in applications on the computer, we may have only allocated a fixed amount of space and cannot exceed it). For this reason, we will need to maintain a count of nodes in the stack (ie the underlying list). | + | With a stack, there sometimes exists a need to cap its total size (especially in applications on the computer, we may have only allocated a fixed amount of space and cannot exceed it). For this reason, we will need to maintain a count of nodes in the stack (ie the underlying list). |
+ | |||
+ | This is why **dll2** exists: to introduce | ||
Additionally, | Additionally, | ||
- | It should also be pointed out that in other applications, | + | It should also be pointed out that in other applications, |
====stack error conditions==== | ====stack error conditions==== | ||
There are two very important operational error conditions a stack can experience: | There are two very important operational error conditions a stack can experience: | ||
- | * __stack **over**flow__: | + | * __stack **over**flow__: |
* __stack **under**flow__: | * __stack **under**flow__: | ||
Line 106: | Line 97: | ||
For this project, we're going to be implementing the stack data structure atop of our recently re-implemented linked list (the doubly linked list). | For this project, we're going to be implementing the stack data structure atop of our recently re-implemented linked list (the doubly linked list). | ||
- | Should you be having any lingering issues with your doubly-linked list implementation, | + | Should you be having any lingering issues with your doubly-linked list implementation, |
- | ====New header file: inc/data.h==== | + | ====inc/stack.h==== |
- | With the introduction | + | To implement a stack, we'll be creating a new type of struct. Continuing our previous |
- | + | ||
- | Here's what's in the file: | + | |
<code c> | <code c> | ||
- | # | + | # |
- | # | + | # |
- | // Status codes for the doubly linked list implementation | + | ////////////////////////////////////////////////////////////////////// |
// | // | ||
- | # | + | // Stack relies on list (which relies on node) to work. |
- | # | + | // See the layers? |
- | # | + | |
- | # | + | |
- | # | + | |
- | # | + | |
- | # | + | |
- | + | ||
- | // Status codes for the stack implementation | + | |
// | // | ||
- | #define | + | #include " |
- | # | + | |
- | # | + | |
- | # | + | |
- | # | + | |
- | # | + | |
- | # | + | |
- | # | + | |
- | // Status codes for the list's display() function modes | + | ////////////////////////////////////////////////////////////////////// |
// | // | ||
- | # | + | // Define the stack struct |
- | # | + | |
- | # | + | |
- | # | + | |
- | # | + | |
- | # | + | |
- | + | ||
- | // custom types (mostly for shortening typing) | + | |
// | // | ||
- | typedef unsigned short int code_t; | + | struct |
- | typedef unsigned long int | + | Node *top; // pointer to top of stack |
- | + | | |
- | #endif | + | |
- | </ | + | |
- | + | ||
- | In addition to the status codes (for list and stack), we also see new defines for display(), better visualizing the numeric modes. | + | |
- | + | ||
- | Finally, there' | + | |
- | + | ||
- | * **code_t** - basically just an unsigned short int, and will expand upon the status codes explored in the dll projects (to include stack status codes too). | + | |
- | * **uli** - nothing short of a shortcut: an unsigned long int. | + | |
- | + | ||
- | ====In inc/ | + | |
- | There is one change (an addition) that has been made to **list.h**, and that is the return of the **qty** element: | + | |
- | + | ||
- | <code c> | + | |
- | struct list { | + | |
- | Node *first; | + | |
- | | + | |
- | | + | |
}; | }; | ||
- | typedef struct list List; // because we deserve nice things | ||
- | </ | ||
- | We're also taking advantage of our new " | + | code_t |
+ | code_t | ||
+ | code_t | ||
- | It should be noted (and stressed) that the utilization of **qty** should JUST be in maintaining a count. You need not re-implement or change the logic of any of your list functionality to base its operations or to rely on **qty** in any way (just as before, if you do you'll lose credit). | + | code_t |
+ | code_t | ||
+ | code_t | ||
- | From the list's point of view, its sole purpose is for show. | + | code_t |
- | With that said, you likely only have to make changes to 4 functions in order to appropriately accommodate **qty**-- any low-level list operation that is responsible for initializing, | ||
- | |||
- | You may make use of the **qty** element to streamline your **display()** function' | ||
- | ====In inc/ | ||
- | |||
- | <code c 1> | ||
- | #ifndef _STACK_H | ||
- | #define _STACK_H | ||
- | |||
- | #include " | ||
- | #include " | ||
- | // (which relies on node) | ||
- | |||
- | struct stack { | ||
- | List | ||
- | Node | ||
- | uli | ||
- | }; // an unbounded stack) | ||
- | typedef struct stack Stack; | ||
- | |||
- | code_t mkstack(Stack **, uli); // create new stack (of max size) | ||
- | code_t cpstack(Stack *, Stack **); // create a copy of an existing stack | ||
- | code_t rmstack(Stack **); // clear and de-allocate an existing stack | ||
- | |||
- | code_t push(Stack **, Node * ); // put new node on top of stack | ||
- | code_t pop (Stack **, Node **); // get (and disconnect) top node off stack | ||
- | |||
- | code_t peek(Stack *, Node **); // get (don't disconnect) top node | ||
- | code_t isempty(Stack *); // determine if the stack is empty or not | ||
#endif | #endif | ||
</ | </ | ||
- | For our stack implementation, just as with our doubly-linked list implementation, we will make increased used of the double pointer in order to achieve passing parameters by address. | + | As indicated, with stacks, suddenly a lot of the underlying details start to be abstracted away. And the total number of unique functions being created also tends to decrease. |
- | This is necessary so that we can free up the return value of **push()** and **pop()** to be used for status (ie look out for stack overflows and underflows). You'll note the extensive deployment of the **code_t** type as the return value for all the stack functions (instead of lengthily having to type out " | + | For our stack implementation, |
+ | |||
+ | This is necessary so that we can free up the return value of **push()** and **pop()** to be used for status (ie look out for stack overflows and underflows). | ||
**peek()** and **isempty()** are being implemented as an exercise to aid in your understanding of stacks. Again, avoid their use except is a means of convenience (or to further optimize your code). The general rule of thumb is that the use of **peek()** and **isempty()** should result in shortening your code in a clear or clever way. | **peek()** and **isempty()** are being implemented as an exercise to aid in your understanding of stacks. Again, avoid their use except is a means of convenience (or to further optimize your code). The general rule of thumb is that the use of **peek()** and **isempty()** should result in shortening your code in a clear or clever way. | ||
Line 222: | Line 148: | ||
In object-oriented programming, | In object-oriented programming, | ||
- | ====list library==== | + | ====inc/data.h==== |
- | Againt, in **src/ | + | With stacks, the following new information has been added to **data.h**: |
- | + | ||
- | ===display() enhancements=== | + | |
- | You are also to implement 4 additional modes to the display() function. | + | |
- | + | ||
- | This means you'll need to expand the current modulus divide by 4 to one of 8. | + | |
- | + | ||
- | The current modes are as follows: | + | |
<code c> | <code c> | ||
- | // modes: 0 display the list forward, no positional values | + | ////////////////////////////////////////////////////////////////////// |
- | // 1 display the list forward, with positional values | + | // |
- | // 2 display | + | // Status codes for the doubly linked stack implementation |
- | // 3 display the list backwards, with positional values | + | // |
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
</ | </ | ||
- | The new modes are (you may want to add these comments to your **display.c** file): | + | __**Technical note**__: Due to space constraints |
- | <code c> | ||
- | // 4 display the list forward, no positional values, in ASCII | ||
- | // 5 display the list forward, with positional values, in ASCII | ||
- | // 6 display the list backwards, no positional values, in ASCII | ||
- | // 7 display the list backwards, with positional values, in ASCII | ||
- | </ | ||
- | |||
- | What has changed? In modes 4-7, instead of displaying the numeric value contained in the node's data element, you are instead to represent it as its ASCII character. | ||
- | |||
- | For example, if there was a numeric 65 stored in the node , in the mode 4-7 representation, | ||
- | |||
- | ==display() output examples based on mode== | ||
- | Let's say we have a list with the following elements: | ||
- | |||
- | first -> 51 -> 49 -> 51 -> 51 -> 55 -> NULL | ||
- | |||
- | ==mode 0: forward, no positions, as numbers== | ||
- | <cli> | ||
- | 51 -> 49 -> 51 -> 51 -> 55 -> NULL | ||
- | </ | ||
- | |||
- | ==mode 1: forward, with positions, as numbers== | ||
- | <cli> | ||
- | [0] 51 -> [1] 49 -> [2] 51 -> [3] 51 -> [4] 55 -> NULL | ||
- | </ | ||
- | |||
- | ==mode 4: forward, no positions, in ASCII== | ||
- | <cli> | ||
- | ' | ||
- | </ | ||
- | |||
- | ==mode 5: forward, with positions, in ASCII== | ||
- | <cli> | ||
- | [0] ' | ||
- | </ | ||
- | |||
- | |||
- | ====List Library unit tests==== | ||
- | As a result of the required changes to **display()** and the incorporation of **qty**, pertinent list unit tests will be enhanced, so you can make use of them to ensure implementation compliance. | ||
- | |||
- | The pertinent list unit tests have been updated. You only need to focus on the following for the list library (remaining list functions need no changes): | ||
- | * unit-mklist.c | ||
- | * unit-append.c | ||
- | * unit-insert.c | ||
- | * unit-obtain.c | ||
- | * unit-display.c | ||
- | The **verify-list.sh** script has been updated to display just these updated unit tests. | ||
====stack library==== | ====stack library==== | ||
Line 306: | Line 187: | ||
* **DLS_CREATE_FAIL** - memory allocation failed (considered in error) | * **DLS_CREATE_FAIL** - memory allocation failed (considered in error) | ||
* **DLS_NULL** - result is NULL (probably in error) | * **DLS_NULL** - result is NULL (probably in error) | ||
- | * **DLS_EMPTY** - result is an empty list (may or may not be in error) | + | * **DLS_EMPTY** - result is an empty list/ |
* **DLS_OVERFLOW** - operation exceeds allocated size of list (may be considered an error) | * **DLS_OVERFLOW** - operation exceeds allocated size of list (may be considered an error) | ||
* **DLS_UNDERFLOW** - operation cannot proceed due to lack of data (may be considered an error) | * **DLS_UNDERFLOW** - operation cannot proceed due to lack of data (may be considered an error) | ||
* **DLS_DEFAULT_FAIL** - default state of unimplemented functions (default error) | * **DLS_DEFAULT_FAIL** - default state of unimplemented functions (default error) | ||
- | * **DLS_FAIL** - some error occurred | + | * **DLS_ERROR** - some error occurred |
+ | * **DLS_INVALID** - invalid state (pointer to stack does not exist) | ||
For example, in the case of " | For example, in the case of " | ||
- | * DLS_FAIL | + | * DLS_ERROR |
* DLS_CREATE_FAIL (a problem has occurred when using malloc()) | * DLS_CREATE_FAIL (a problem has occurred when using malloc()) | ||
* DLS_NULL (no memory allocated, so stack cannot be anything but NULL) | * DLS_NULL (no memory allocated, so stack cannot be anything but NULL) | ||
- | ALL THREE states must be returned from the function in question should such an occurrence take place. | + | ALL THREE states must be returned from the function in question should such an occurrence take place (in addition, various underlying |
- | + | ||
- | It is also intended that when handling stack status codes, any list status codes will also be present | + | |
====Stack library unit tests==== | ====Stack library unit tests==== | ||
In **testing/ | In **testing/ | ||
Line 359: | Line 238: | ||
It is also highly recommended to undertake as it will give you further experience working with these concepts. | It is also highly recommended to undertake as it will give you further experience working with these concepts. | ||
- | Note this is a DIFFERENT approach than you would have taken in the program with sll2- you're to use stack functionality to aid you with the heavy lifting. | + | Note this is a DIFFERENT approach than you would have taken in the program with sll2 and dll1- you're to use stack functionality to aid you with the heavy lifting. |
=====Expected Results===== | =====Expected Results===== | ||
- | To assist you in verifying a correct implementation, | + | To assist you in verifying a correct implementation, |
- | + | ||
- | ====node library==== | + | |
- | Here is what you should get for node: | + | |
- | + | ||
- | < | + | |
- | lab46: | + | |
- | ==================================================== | + | |
- | = Verifying Doubly-Linked Node Functionality | + | |
- | ==================================================== | + | |
- | [mknode] Total: | + | |
- | [cpnode] Total: | + | |
- | [rmnode] Total: | + | |
- | ==================================================== | + | |
- | | + | |
- | ==================================================== | + | |
- | lab46: | + | |
- | </ | + | |
- | + | ||
- | As no coding changes were needed in the node library, these results | + | |
- | + | ||
- | ====list library==== | + | |
- | Here is what you should get for list: | + | |
- | + | ||
- | < | + | |
- | lab46: | + | |
- | ==================================================== | + | |
- | = Verifying Doubly-Linked List Functionality | + | |
- | ==================================================== | + | |
- | [mklist] Total: | + | |
- | [append] Total: | + | |
- | [insert] Total: | + | |
- | [obtain] Total: | + | |
- | | + | |
- | ==================================================== | + | |
- | | + | |
- | ==================================================== | + | |
- | lab46: | + | |
- | </ | + | |
- | + | ||
- | Due to the re-introduction of **qty** into list (impacting actions performed by **mklist()**, | + | |
- | + | ||
- | Remember though- aside from the minor change of adding **qty** and enhancing **display()**, | + | |
====stack library==== | ====stack library==== | ||
Line 410: | Line 247: | ||
<cli> | <cli> | ||
- | lab46: | + | lab46: |
- | =================================================== | + | ====================================================== |
- | = | + | = Verifying Doubly-Linked Stack Functionality |
- | =================================================== | + | ====================================================== |
- | [mkstack] Total: | + | |
- | [cpstack] Total: | + | [push] Total: |
- | [rmstack] Total: | + | |
- | [push] Total: | + | [cpstack] Total: |
- | [pop] Total: | + | [peek] Total: |
- | [peek] Total: | + | [isempty] Total: |
- | [isempty] Total: | + | |
- | =================================================== | + | ====================================================== |
- | [RESULTS] Total: | + | |
- | =================================================== | + | ====================================================== |
lab46: | lab46: | ||
</ | </ | ||
- | =====Submission | + | =====Submission===== |
- | To be successful in this project, the following criteria must be met: | + | {{page> |
- | * Project must be submit on time, by the posted deadline. | ||
- | * Late submissions will lose 25% credit per day, with the submission window closing on the 4th day following the deadline. | ||
- | * All code must compile cleanly (no warnings or errors) | ||
- | * all requested functions must be implemented in the related library | ||
- | * all requested functionality must conform to stated requirements (either on this project page or in comment banner in source code files themselves). | ||
- | * Executed programs must display in a manner similar to provided output | ||
- | * output formatted, where applicable, must match that of project requirements | ||
- | * Processing must be correct based on input given and output requested | ||
- | * Output, if applicable, must be correct based on values input | ||
- | * Code must be nicely and consistently indented (you may use the **indent** tool) | ||
- | * Code must be commented | ||
- | * Any "to be implemented" | ||
- | * these "to be implemented" | ||
- | * Sufficient comments explaining the point of provided logic **MUST** be present | ||
- | * Track/ | ||
- | * Submit a copy of your source code to me using the **submit** tool (**make submit** will do this) by the deadline. |