Академический Документы
Профессиональный Документы
Культура Документы
A stack is a restricted linear list in which all additions and deletions are made at one end, the top. If we insert a series of data items into a stack and then remove them, the order of the data is reversed. This reversing attribute is why stacks are known as last in, first out (LIFO) data structures.
Operations on stacks
There are four basic operations, stack, push, pop and empty, that we define in this chapter.
The push operation inserts an item at the top of the stack. The following shows the format.
PUSH(STACK,TOP,MAXSTK,ITEM) 1.[Stack already filled] If TOP=MAXSTK, then: print OVERFLOW, and Return. 2.Set TOP:=TOP+1 [increases TOP by 1] 3.Set STACK[TOP]:=ITEM [insert ITEM in new TOP position] 4.Return
The pop operation deletes the item at the top of the stack. The following shows the format.
POP(STACK,TOP,ITEM) 1.[Stack has an item to be removed] If TOP=0, then: print UNDERFLOW, and Return. 2.Set ITEM:=STACK[TOP] [Assigns TOP element to ITEM] 3.Set TOP:=TOP-1[Decreases TOP by 1] 4.Return
The empty operation checks the status of the stack. The following shows the format.
This operation returns true if the stack is empty and false if the stack is not empty.
12.7
Stack ADT
We define a stack as an ADT as shown below:
12.8
Example 12.1 Figure 12.6 shows a segment of an algorithm that applies the previously defined operations on a stack S.
Stack applications
Stack applications can be classified into four broad categories: reversing data, pairing data, postponing data usage and backtracking steps. We discuss the first two in the sections that follow.
Reversing data items Reversing data items requires that a given set of data items be reordered so that the first and last items are exchanged, with all of the positions between the first and last also being relatively exchanged. For example, the list (2, 4, 7, 1, 6, 8) becomes (8, 6, 1, 7, 4, 2).
12.10
Example 12.2
12.11
12.12
Pairing data items We often need to pair some characters in an expression. For example, when we write a mathematical expression in a computer language, we often need to use parentheses to change the precedence of operators. The following two expressions are evaluated differently because of the parentheses in the second expression:
When we type an expression with a lot of parentheses, we often forget to pair the parentheses. One of the duties of a compiler is to do the checking for us. The compiler uses a stack to check that all opening parentheses are paired with a closing parentheses.
12.13
Example 12.3 Algorithm 12.2 shows how we can check if all opening parentheses are paired with a closing parenthesis.
12.14
12.15
Stack implementation
At the ADT level, we use the stack and its four operations; at the implementation level, we need to choose a data structure to implement it. Stack ADTs can be implemented using either an array or a linked list. Figure 12.7 shows an example of a stack ADT with five items. The figure also shows how we can implement the stack. In our array implementation, we have a record that has two fields. The first field can be used to store information about the array. The linked list implementation is similar: we have an extra node that has the name of the stack. This node also has two fields: a counter and a pointer that points to the top element.
12.16
QUEUES
A queue is a linear list in which data can only be inserted at one end, called the rear, and deleted from the other end, called the front. These restrictions ensure that the data is processed through the queue in the order in which it is received. In other words, a queue is a first in, first out (FIFO) structure.
Operations on queues
Although we can define many operations for a queue, four are basic: queue, enqueue, dequeue and empty, as defined below. The queue operation
The queue operation creates an empty queue. The following shows the format.
The enqueue operation inserts an item at the rear of the queue. The following shows the format.
QINSERT(QUEUE,N,FRONT,REAR,ITEM) This procedure inserts an element ITEM into a queue 1) [queue already filled?] If FRONT=1 and REAR=N , or if FRONT=REAR+1 Then: write OVERFLOW and return. 2) [find new value of REAR] If FRONT:=NULL [then queue initially empty] Set FRONT:=1 and REAR:=1 Else if REAR=N , then : Set REAR:=1 Else: Set REAR:=REAR+1 [end of if structure] 3) Set QUEUE[REAR]:=ITEM[this inserts new element] 4) RETURN
The dequeue operation deletes the item at the front of the queue. The following shows the format.
QDELETE(QUEUE,N,FRONT,REAR,ITEM) This procedure deletes an element from a queue and assign it to the variable item
1)[queue already empty?] If FRONT:=NULL Then: write UNDERFLOW and return 2)Set ITEM:=QUEUE[FRONT] 3)[find new value of FRONT] if FRONT=REAR , then:[queue has only one element] Set FRONT:=NULL and REAR:=NULL else if FRONT=N, then: set FRONT:=1 else set FRONT:=FRONT+1 [end of if structure 4) RETURN
The empty operation checks the status of the queue. The following shows the format.
This operation returns true if the queue is empty and false if the queue is not empty.
12.24
Queue ADT
We define a queue as an ADT as shown below:
12.25
Example 12.4 Figure 12.12 shows a segment of an algorithm that applies the previously defined operations on a queue Q.
Queue applications
Queues are one of the most common of all data processing structures. They are found in virtually every operating system and network and in countless other areas. For example, queues are used in online business applications such as processing customer requests, jobs and orders. In a computer system, a queue is needed to process jobs and for system services such as print spools.
12.27
Example 12.5
12.28
12.29
Example 12.6 Another common application of a queue is to adjust and create a balance between a fast producer of data and a slow consumer of data. For example, assume that a CPU is connected to a printer. The speed of a printer is not comparable with the speed of a CPU. If the CPU waits for the printer to print some data created by the CPU, the CPU would be idle for a long time. The solution is a queue. The CPU creates as many chunks of data as the queue can hold and sends them to the queue. The CPU is now free to do other jobs. The chunks are dequeued slowly and printed by the printer. The queue used for this purpose is normally referred to as a spool queue.
12.30
Queue implementation
At the ADT level, we use the queue and its four operations at the implementation level. We need to choose a data structure to implement it. A queue ADT can be implemented using either an array or a linked list. Figure 12.13 on page 329 shows an example of a queue ADT with five items. The figure also shows how we can implement it. In the array implementation we have a record with three fields. The first field can be used to store information about the queue.
The linked list implementation is similar: we have an extra node that has the name of the queue. This node also has three fields: a count, a pointer that points to the front element and a pointer that points to the rear element.
12.31
TREES
A tree consists of a finite set of elements, called nodes (or vertices) and a finite set of directed lines, called arcs, that connect pairs of the nodes.
We can divided the vertices in a tree into three categories: the root, leaves and the internal nodes. Table 12.1 shows the number of outgoing and incoming arcs allowed for each type of node.
12.34
Each node in a tree may have a subtree. The subtree of each node includes one of its children and all descendents of that child. Figure 12.21 shows all subtrees for the tree in Figure 12.20.
12.37
Figure 12.23 shows eight trees, the first of which is an empty binary tree (sometimes called a null binary tree).
12.39
A binary tree traversal requires that each node of the tree be processed once and only once in a predetermined sequence. The two general approaches to the traversal sequence are depth-first and breadth-first traversal.
Example 12.10
Figure 12.25 shows how we visit each node in a tree using preorder traversal. The figure also shows the walking order. In preorder traversal we visit a node when we pass from its left side. The nodes are visited in this order: A, B, C, D, E, F.
Example 12.11 Figure 12.26 shows how we visit each node in a tree using breadth-first traversal. The figure also shows the walking order. The traversal order is A, B, E, C, D, F.
Huffman coding
Huffman coding is a compression technique that uses binary trees to generate a variable length binary code from a string of symbols. We discuss Huffman coding in detail in Chapter 15.
12.43
Expression trees An arithmetic expression can be represented in three different formats: infix, postfix and prefix. In an infix notation, the operator comes between the two operands. In postfix notation, the operator comes after its two operands, and in prefix notation it comes before the two operands. These formats are shown below for addition of two operands A and B.
12.44
Example 12.12 Figure 12.29 shows some binary trees that are BSTs and some that are not. Note that a tree is a BST if all its subtrees are BSTs and the whole tree is also a BST.
A very interesting property of a BST is that if we apply the inorder traversal of a binary tree, the elements that are visited are sorted in ascending order. For example, the three BSTs in Figure 12.29, when traversed in order, give the lists (3, 6, 17), (17, 19) and (3, 6, 14, 17, 19).
i
An inorder traversal of a BST creates a list that is sorted in ascending order.
12.48
Another feature that makes a BST interesting is that we can use a version of the binary search we used in Chapter 8 for a binary search tree. Figure 12.30 shows the UML for a BST search.
12.50
BST implementation
BSTs can be implemented using either arrays or linked lists. However, linked list structures are more common and more efficient. The implementation uses nodes with two pointers, left and right.
12-8 GRAPHS
A graph is an ADT made of a set of nodes, called vertices, and set of lines connecting the vertices, called edges or arcs. Whereas a tree defines a hierarchical structure in which a node can have only one single parent, each node in a graph can have one or more parents. Graphs may be either directed or undirected. In a directed graph, or digraph, each edge, which connects two vertices, has a direction from one vertex to the other. In an undirected graph, there is no direction. Figure 12.32 shows an example of both a directed graph (a) and an undirected graph (b).
12.52
Example 12.13 A map of cities and the roads connecting the cities can be represented in a computer using an undirected graph. The cities are vertices and the undirected edges are the roads that connect them. If we want to show the distances between the cities, we can use weighted graphs, in which each edge has a weight that represents the distance between two cities connected by that edge.
Example 12.14
Another application of graphs is in computer networks (Chapter 6). The vertices can represent the nodes or hubs, the edges can represent the route. Each edge can have a weight that defines the cost of reaching from one hub to an adjacent hub. A router can use graph algorithms to find the shortest path between itself and the final destination of a packet.
12.54