Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
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.