Download Chapter 4 Linked Stacks and Queues 链式栈和链式队列

Document related concepts

Red–black tree wikipedia , lookup

Lattice model (finance) wikipedia , lookup

Quadtree wikipedia , lookup

Interval tree wikipedia , lookup

Binary search tree wikipedia , lookup

B-tree wikipedia , lookup

Linked list wikipedia , lookup

Transcript
Chapter 4 Linked Stacks and Queues
链栈和链队列
1.
2.
3.
4.
5.
6.
Pointers and linked structures(指针和链结构)
Linked stacks (链栈)
Linked stacks with safeguards
Linked queues (链队列)
Application: polynomial arithmetic
Abstract data types and implementations
内存溢出(overflow)问题
• When using arrays to implement data structures,
we must fix the sizes of the arrays.
- if the size is not big enough, then overflow
- if the size is too big, then much of the space is not
used
Solution: pointers, dynamic memory allocation.
Linked Structures
A linked structure is made up of nodes,
entry
Store data
next
A pointer pointing
to the next node
We shall use a struct to implement nodes:
struct Node {
// data members
Node_entry entry;
Node *next;
// constructors
Type of
entries
Node();
Node(Node_entry item, Node *add_on = NULL);
};
Default value
Node Constructors:
Node::Node() {
next = NULL;
}
Node::Node(Node_entry item, Node *add_on) {
entry = item;
next = add_on;
}
Linked Stacks
• To implement pop and push, we need to
decide “Where is the top node”?
• Take top_node at top node is much
easier.
Push “New node”
new_top->next = top_node;
top_node = new_top;
// Obs! The order is important!
Pop up a node:
top_node = top_node->next;
Class declaration for linked stacks
New node is added
as the first node.
How about the following code of popping:
if (top_node == NULL) return underflow;
top_node = top_node->next;
return success;
This node is lost! Garbage is
created!
Problem Example
Garbage created: when stack small goes out
of scope, the space for some_data becomes
garbage.
Solution: provide a destructor.
1. A destructor is automatically executed on
objects of the class when the objects go out of
scope.
2. It is often used to clean up the space that
otherwise become garbage.
Danger in Assignment
Random address
after inner_stack
goes out of scope.
Misbehaviors:
1. Lost data space;
2. outer_stack.top_node becomes a random address
when the destructor on inner_stack delete
outer_stack.
The reason is that the assignment here copies
references (has reference semantics), not value
(value semantics).
The solution is to provide a overloading assignment
that has value semantics (only copies data).
Prototype and outline:
void Stack::operator=(const Stack &original);
1. Make a copy of the data in original: a) first case:
original is empty; b) copy the first node; c) run a
loop to copy every node in original.
2. Clear out any data in the Stack being assigned to;
3. Move the newly copied data to the Stack object.
Obs! Don’t release data before copy finished.
Otherwise, it will not work for x = x.
The default copy operation copies every data
member of a class (has reference semantics
here):
1. Copy shares nodes with vital_data;
2. When destructor is applied to copy,
vital_data is also destroyed.
Solution: Define its own copy constructor.
Stack :: Stack(const Stack &original);
//The Stack is initialized as a copy of original
Linked stack copy constructor
Modified linked-stack specification
Linked queues
Append and Serve:
Extended linked queue
Polish notation for expressions
• Writing all operators either before their operands or
after them is called Polish notation.
• prefix form: operators are before their operands
• Postfix form(reverse Polish form): operators are after
their operands.
• a*b becomes * a b (prefix) or a b * (postfix)
• a + b *c becomes a b c * + (postfix)
• a*(b-c)+d becomes a b c - * d + (postfix)
Converting infix form to postfix form
• Operands are output directly
• Operators are suspended until their operands are
found
• When do you know the operands are read? Another
operator is read.
• Use a stack to remember the operators.
• When another operator is read, compare the
priorities of the operator and the operator on the top
of the stack. Pop if the top operator has higher
priority.
• Exercise. Design an algorithm that converting
infix expressions (including parentheses) to
postfix expressions.
Advantages of postfix form
•
•
•
•
No parentheses, no priorities
Evaluation is done from left to right
Evaluation is easy and efficient
Used in compilers, infix expressions are
transformed into postfix form
Evaluating postfix expressions
• Read the expression from left to right, remember
the operands until their operator is found later;
• Natural way to remember operands: use stack, and
push operands into the stack;
• When an operator is read, pop the operands and
push back the result;
• Read on until the end of the expression.
Application: Polynomial arithmetic
• Operations: Polynomial addition, subtraction,
multiplication and division (+, -, *, /);
• Use reverse Polish notation: operands are
entered before the operations;
• As for the calculator for numbers, operands
are pushed into a stack, and when an operation
is performed, operands are popped up and the
result is pushed back.
Data Structures for Polynomial
A polynomial is a list of terms, which consists
of a coefficient and an exponent.
The Term is implemented as
struct Term {
int degree;
double coefficient;
Term (int exponent = 0; double scalar = 0);
}
Then we need to perform operations on lists of
Terms. The operations have the properties, for
example, when forming a new list for the sum of
two lists:
• Removing the first entry from a list;
• Inserting new entries at the end of a list.
So, polynomials are treated as queues.
Contiguous or linked queues?
No clear bound for contiguous queues.
We represent a polynomial as an extended linked
queue of terms.
polynomials as linked queue of terms.
zero polynomial
However, we don’t want to provide queue methods
for client programs, for example, not serve(),
although we would like to use queue methods to
implement Polynomials.
Use private inheritance: define the class Polynomial
to be privately inherited from the class
Extended_queue and queue methods are not
available to client programs.
Polynomials as a class
class Polynomial:private Extended_queue {
public:
void read();
void print() const;
void equals_sum(Polynomial p, Polynomial q);
void equals_diff(Polynomial p, Polynomial q);
void equals_prod(Polynomial p, Polynomial q);
Error_code equals_quot(Polynomial p, Polynomial q);
int degree() const;
private:
void mult_term(Polynomial p, Term t);
};
To make things easier, we assume that
• Polynomials are stored in the order of
decreasing exponent within the linked queue;
• No two terms have the same exponent;
• No term has a zero coefficient.
The main program
ADT and their implementations
ADT includes two parts:
How the components are related each other
and
what operations can be performed on the elements
of the ADT.
No mention how it is implemented.
Contiguous queues and linked queues are all its
implementation.
The process of implementing an ADT
Abstract level of a type definition
Definition of ADT
Data Structure level
Implementation level
Decide on a structure to
model our data type
Decide on the details of how our
data structure will be stored
For queues, we decide to use array or linked
structures for the implementation at the data
structure level, so the methods can be analyzed.
In the implementation level, we decide more details
that lead to a class definition.
本章主要内容
• 掌握链栈和链队列的实现:实现中需要注意的
问题;
• 掌握ADT从概念的抽象到实现过程;
• 掌握数据结构的应用:从分析问题到数据结构
的选择,最后新的数据结构的实现,如多项式
ADT的定义与实现。
• 实验课任务:实现多项式ADT.