Data Structures And Number Systems
© Copyright Brian Brown,
1984-2000. All rights reserved.
STACKS
A stack is used to provide temporary storage space for values. It
is defined as a data structure which operates on a first in,
last out basis. Its uses a single pointer (index) to keep
track of the information in the stack.
The basic operations associated with a stack are,
The following diagram shows an empty stack of four locations. It looks just like an array, and it has an index pointer pointing to the beginning of the stack (called the TOP of the stack).
+--------+ | | <------- Stack Pointer +--------+ | | +--------+ | | +--------+ | | +--------+
Pushing items onto the stack
The stack pointer is considered to be pointing to a free (empty)
slot in the stack. A push operation thus involves copying data
into the empty slot of the stack, then adjusting the stack
pointer to point to the next free slot.
Module Push stack[stack_pointer] = data; stack_pointer = stack_pointer + 1; Module End
Lets push the value 45 onto the stack. [Note: The stack could hold any data type, not necessarily decimal numbers. We have used numbers for simplicity]. The stack now looks like
+--------+ | 45 | +--------+ | | <------- Stack Pointer +--------+ | | +--------+ | | +--------+
Note how the stack pointer has been adjusted to point to the next free location in the stack. [Note: for the time being we are ignoring certain problems. We will address these shortly!!!].
Removing items from the stack
To remove an item, first decrement (subtract 1 from) the stack
pointer, then extract the data from that position in the stack.
Module Remove stack_pointer = stack_pointer - 1; data = stack[stack_pointer]; Module End
Time now to address the problems of the above
implementation
There are a number of problems associated with the above routines
for pushing and removing items.
There are a number of solutions to this problem. We shall present a simplified solution. We do not argue that it is the best, just that it is one of a possible number of solutions.
Comment: Assume that the array elements begin at 1 Comment: Assume that the maximum elements of the stack is MAX Var: stack[MAX] : Integer; Module Initialize stack_pointer = 1; Module End Module Push if stack_pointer >= MAX then return error else begin stack[stack_pointer] = data; stack_pointer = stack_pointer + 1; end Module End Module Remove if stack_pointer <= 1 then return error else begin stack_pointer = stack_pointer - 1; data = stack[stack_pointer]; end Module End
QUEUES
Everybody has experience with queues as they are common place.
Queues occur in cafeterias, petrol stations, shopping centres,
anyplace where many people (customers) line up for few resources
(cashier's, salespeople, petrol pumps etc).
The purpose of a queue is to provide some form of buffering. Typical uses of queues in computer systems are,
A queue is defined as a data structure which holds a series of items to be processed on a first in first out basis (though some queues can be sorted in priority). The operations associated with a queue are,
The following diagram shows an empty queue. It is identified as a series of ten locations, and two pointers named front and rear. These two pointers keep track of where the front and rear of the queue is.
1 2 3 4 5 6 7 8 9 10 +---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+ +---+ | 1 | Front +---+ +---+ | 10| Rear +---+
The front pointer is used to delete items, and the rear pointer insert items. Inserting two items called A and B will rearrange the queue to look like,
1 2 3 4 5 6 7 8 9 10 +---+---+---+---+---+---+---+---+---+---+ | A | B | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+ +---+ | 1 | Front +---+ +---+ | 2 | Rear +---+
The pseudo-code for the various queue operations follows.
module initialize count = 0 head = 1 rear = size of queue end module initialize module insert if count = size of queue queue is full and do not insert else begin increment count increment rear if rear > size of queue rear = 1 endif insert data at queue[rear] endif end module insert module remove if count = 0 queue is empty and do not remove else begin data = queue[front] decrement count increment front if front > size of queue front = 1 endif endif end module remove module count return count end module count module free_space return queue.size - count end module free_space
The implementation of this is left to the student as a programming exercise.
LINKED LISTS
Data structures can be arranged in memory in a variety of
different ways. Each method has advantages and disadvantages.
Arrays for example seem easy to use, where each element is stored
sequentially in memory.
This type of approach is not efficient in larger computer systems, where a number of users share main memory. In such circumstances, there may not be enough contiguous main memory left to hold a sequentially stored data structure like an array (but there could be enough if all the small free blocks were moved into one large block).
One way to overcome this is to link all elements of data together. Data is arranged into records, and a special item is added to each record called a pointer (a link field), which contains a link to the next record etc. Renaming each record as a node and we have a complex data structure called a linked list.
A linked list is a series of nodes connected together via pointers. Pictorially, it looks like,
Node 1 +---+ Node 2 +---+ Node n +--------+--+ | +--------+--+ | +--------+--+ | | ------+ | | ------+ | | | +--------+--+ +--------+--+ +--------+--+ Data Link Data Lnk Data Lnk
In Pascal, a node definition looks like,
type ptr = ^node; node = record data : string[20]; next : ptr; end;
The following Pascal program declares three nodes, inserts data into each of them, then using a pointer, cycles through the chain from node to node printing out the contents of each node. The value 0 is always stored in the last node of a chain, to indicate the end of the list.
program linked_list; type ptr = ^node; node = record data : string[20]; next : ptr; end; var node1, node2, node3 : node; nodeptr : ptr; begin node1.data := 'Welcome '; node1.next := @node2; node2.data := 'to '; node2.next := @node3; node3.data := 'Linked Lists.'; node3.next := nil; nodeptr := @node1; while nodeptr <> nil do begin write( nodeptr^.data ); nodeptr := nodeptr^.next; end; writeln; end.
Linked lists are used in a wide variety of applications.
An advantage of storing data using a linked list is that the key sequence can be altered by changing the pointers, not by moving data nodes. This means sorting data is quick, but searching is slower as you must follow the chain from node to node.
HASHING
Hashing is a technique used to improve data access times. Rather
than sorting the data according to a key, it computes the
location of the data from the key. In simple terms, it computes
an index value from the key of the desired record. At that
index value, the record is stored/retrieved.
If we had an array of 1000 elements, we would expect our hash function (the method used to calculate the index value) to evenly distribute the keys over this range. In practice this is difficult to achieve. It is possible that two different search keys might generate the same hash value (ie, index), and we call this a collision.
The size of the table (array) is generally a prime number, as this has the least probability of creating collisions.
The following code segment defines an array of records in Pascal which will be used to demonstrate hashing.
const size = 511; type data = record name : string[20]; age : integer; end; hashtable = array[1..size] of data;
Next, lets initialize the table with zero's, so this makes it easy to see if information is already stored at a particular element (important when inserting data later).
procedure initialize ( var Table : hashtable ); var i : integer; begin for i := 1 to size do begin Table[i].name := ' '; Table[i].age := 0; end; end;
The procedure insert will take the hash value and the data and insert it into the table. If the position is already occupied (ie, a collision occurs) the table will be searched from that point onwards till an empty slot occurs.
procedure insert ( Position : integer; Element : data ; var Table : hashtable ); begin while Table[Position].name[1] <> ' ' do Position := (Position + 1) mod size; Table[Position] := Element; end;
The procedure hash will generate a hash value from a given data record. In deciding this, it must generate a value between 1 and 511. Obviously, we cannot use the age field of the record, this will generate too many collisions. The best method is to add up the value of all the characters in the persons name, then extract nine bits from it (2^9 = 512) to generate the index value.
procedure hash ( var Position : integer ; Element : data ; var Table : hashtable ); var i : integer; begin i := 1; position := 0; while i < 20 do position := position + ord(Element.name[i]); position := position mod 511; end;
The remaining procedures to search and delete are left as a
programming exercise for the student.
INDEXED SEQUENTIAL
This method seeks to make a direct access file appear like a
sequence file. The sequencing is achieved via an index table,
which holds the keys of the records and their position within the
file.
A program reads the index sequentially, and when it locates the key it desires, it reads the record from the indicated position.
The advantages of this method are,
FILE MERGING
This is the process of merging two or more input files into a
single output file (which are normally all sequential in nature).
The files to be merged are first sorted using the same key
sequence, which is preserved in the output file.
A pseudo-code example for a 2-way merge is shown below.
program two_way merge begin read 1st record of infile1, name as rec1 read 1st record of infile2, name as rec2 while rec1 or rec2 is not an end-of-record begin if rec1.key < rec2.key begin write rec1 to outfile read new rec1 from infile1 end else begin write rec2 to outfile read new rec2 from infile2 end endif endwhile write end-of-record to outfile end program two_way merge
Home | Other Courses | Feedback | Notes | Tests
© Copyright Brian Brown, 1984-2000. All rights
reserved.