Download
slide1 n.
Skip this Video
Loading SlideShow in 5 Seconds..
Chapter 6 LISTS AND STRINGS PowerPoint Presentation
Download Presentation
Chapter 6 LISTS AND STRINGS

Chapter 6 LISTS AND STRINGS

137 Views Download Presentation
Download Presentation

Chapter 6 LISTS AND STRINGS

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

  1. Chapter 6 LISTS AND STRINGS 1. List Specifications 2. List Implementations (a). Class Templates (b). Contiguous (c). Simply Linked (d). Simply Linked with Position Pointer (e). Doubly Linked

  2. Chapter 6 LISTS AND STRINGS 3. Strings 4. Application: Text Editor 5. Linked Lists in Arrays 6. Application: Generating Permutations 7. Pointers and Pitfalls

  3. 6.1 List Definition DEFINITION A listof elements of type Tis a finite sequence of elements of Ttogether with the following operations: 1.Construct the list, leaving it empty. 2. Determine whether the list is empty or not. 3. Determine whether the list is full or not. 4. Find the size of the list. 5.Clear the list to make it empty. 6.Insert an entry at a specified position of the list. 7.Remove an entry from a specified position in the list. 8.Retrieve the entry from a specified position in the list. 9.Replace the entry at a specified position in the list. 10.Traverse the list, performing a given operation on each entry.

  4. Comparison with Standard Template Library: ◆The STL list provides only those operations that can be implemented efficiently in a List implementation known as doubly linked, which we shall study shortly. ◆The STL list does not allow random access to an arbitrary list position. ◆The STL vector, does provide some random access to a sequence of data values, but not all the other capabilities we shall develop for a List. ◆In this way, our study of the List ADT provides an introduction to both the STL classes list and vector.

  5. Method Specifications List :: List( ); Post: The List has been created and is initialized to be empty. void List :: clear(); Post: All List entries have been removed; the List is empty.

  6. bool List :: empty() const; Post: The function returns true or false according to whether the List is empty or not. bool List :: full() const; Post: The function returns true or false according to whether the List is full or not. int List :: size() const; Post: The function returns the number of entries in the List.

  7. Position Number in a List ◆To find an entry in a list, we use an integer that gives its position within the list. ◆We shall number the positions in a list so that the first entry in the list has position 0, the second position 1, and so on. ◆Locating an entry of a list by its position is superficially like indexing an array, but there are important differences. If we insert an entry at a particular position, then the position numbers of all later entries increase by 1. If we remove an entry, then the positions of all following entries decrease by 1.

  8. ◆The position number for a list is defined without regard to the implementation. For a contiguous list, implemented in an array, the position will indeed be the index of the entry within the array. But we will also use the position to find an entry within linked implementations of a list, where no indices or arrays are used at all.

  9. Error_codeList::insert(int position, const List_entry &x); Post: If the List is not full and 0 position n, where n is the number of entries in the List, the function succeeds:Any entry formerly at position and all later entries have their position numbers increased by 1, and x is inserted at position in the List. Else: The function fails with a diagnostic error code.

  10. Error_codeList :: remove ( int position, List_entry&x ); Post: If0≤position<n, where n is the number of entries in the List, the function succeeds: The entry at position is removed from the List, and all later entries have their position numbers decreased by 1. The parameter x records a copy of the entry formerly at position. Else: The function fails with a diagnostic error code.

  11. Error_codeList :: retrieve(int position, List_entry &x)const; Post: If0≤position<n, where n is the number of entries in the List, the function succeeds: The entry at position is copied to x; all List entries remain unchanged. Else: The function fails with a diagnostic error code.

  12. Error_codeList :: replace(int position, const List_entry &x); Post: If0≤position<n, where n is the number of entries in the List, the function succeeds: The entry at position is replaced by x; all other entries remain unchanged. Else: The function fails with a diagnostic error code. void List::traverse(void (*visit)(List entry &)); Post: The action specified by function *visit has been performed on every entry of the List, beginning at position 0 and doing each in turn.

  13. 6.2 Implementations of Lists Class Templates ◆A C++ template construction allows us to write code, usually code to implement a class, that uses objects of an arbitrary, generic type. ◆In template code we utilize a parameter enclosed in angle brackets< > to denote the generic type. ◆Later, when a client uses our code, the client can substitute an actual type for the template parameter. The client can thus obtain several actual pieces of code from our template, using different actual types in place of the template parameter.

  14. Example: We shall implement a template class List that depends on one generic type parameter. A client can then use our template to declare several lists with different types of entries with declarations of the following form: List<int> rst list; List<char> second list;

  15. Templates provide a new mechanism for creating generic data structures, one that allows many different specializations of a given data structure template in a single application. The added generality that we get by using templates comes at the price of slightly more complicated class specifications and implementations. 连续/顺序(存储)的 One-dimensional arrays Contiguous(storage) Implementation

  16. template <class List_entry> class List { public: // methods of the List ADT List( ); int size( ) const; bool full( ) const; bool empty( ) const; void clear( ); void traverse(void (*visit)(List_entry &)); Error_code retrieve(int position, List_entry &x); Error_code replace(int position, const List_entry &x); Error_code remove(int position, List_entry &x); Error_code insert(int position, const List_entry &x); 求顺序表的长度 判顺序表是否已"满" 判顺序表是否为“空" 清空顺序表 遍历顺序表 查找表中第position 个元素存入x 将表中第position 个元素值修改为x 删除表中第position 个元素,其值存入x 将x插入表中 令其成为第 position个元素

  17. protected: // data members for a contiguous list implementation int count; List_entry entry[max_list]; }; template <class List_entry> int List<List_entry>::size( ) const // Post: The function returns the number of entries in the List . { return count; }

  18. template <class List_entry> Error_code List<List_entry> ::insert(int position, const List_entry &x) /* Post: If the List is not full and 0 ≤ position ≤ n; where n is the number of entries in the List , the function succeeds: Any entry formerly at position and all later entries have their position numbers increased by 1 and x is inserted at position of the List . Else: The function fails with a diagnostic Error_code. */ { if (full( )) return overflow; if (position < 0 || position > count) return range_error; for (int i=count-1; i >= position; i--) entry[i +1] = entry[i]; entry[position] = x; count++; return success; }

  19. template <class List_entry> void List<List_entry>::traverse(void (*visit)(List_entry &)) /* Post: The action specified by function(*visit) has been performed on every entry of the List , beginning at position 0 and doing each in turn. */ { for (int i=0; i<count; i++) (*visit)(entry[i]); } Performance of Methods In processing a contiguous list with n entries:  insert and remove operate in time approximately proportional to n.  List, clear, empty, full, size, replace, and retrieve operate in constant time.

  20. Please follow the Error_code insert(int position, const List_entry &x) write by yourselves: Error_code retrieve(int position, List_entry &x); Error_code replace(int position, const List_entry &x); Error_code remove(int position, List_entry &x); Application: ContiguousList 设顺序表la和lb分别表示整数集合A和B,求:A=A∪B。 算法思路:集合中的元素是无重复的,可将Lb表中的元素从表尾起逐个删除,并在La表查找被删元素b,若找不到,则将元素b插入La表,否则不必插入,完成后集合B为空。

  21. 在 List类中增加一个成员函数(方法):Find 在class List_entry中 应当有定义 template <class List_entry> int List<List_entry>::Find(const List_entry &x) // 查找值为x的元素:返回-1没找到,否则为x在表中的位置 { int i=0; while( i<count && entry[i]!= x )i++; if(i<count) return i; else return -1; } 下面给出:产生若干互不相等的随机整数(集合元素)插入表的函数:CrtSetList ;进行集合“并”运算的函数:SetUnion及主函数main()的源代码。

  22. #include <stdlib.h> #include <time.h> #include "SQList.h" void CrtSetList(List<int>&,int); // 产生集合元素插入表的原型声明 void SetUnion(List<int>&,List<int>&); // 集合"并"运算的原型声明 void visit(int &i); void main() { // 声明List对象La,Lb,类参数List_entry用<int>实例化 List<int> La,Lb; // La,Lb代表集合 int s1, s2; // s1, s2是存放La,Lb大小的变量 time_t t; srand((unsigned)time(&t)); // 初始化随时间变化的随机数种子 cout<<"Please input Size of SetA && SetB =? =? (<=15)"; cin>>s1>>s2; // 输入集合A,B元素数<=15,以保证"并"后La的元素数<=30

  23. cout<<"\nSet A = { "; // 输出集合A的名称 CrtSetList(La,s1); // 创建集合A并输出集合元素 cout<<"}\nSet B = { "; // 输出集合B的名称 CrtSetList(Lb,s2); SetUnion(La,Lb); // 求集合A与集合B的"并" cout<<"}\n\n A Union B = { "; La.traverse(visit); cout<<" }\n"; }

  24. void CrtSetList(List<int>&L,int n) // 为集合产生n个互不相等的整数插入顺序表 { int x,i,j ; for(i=0; i<n; i++) //用随机数发生器产生n个集合元素,不得重复 { do{ x=rand() % 37; } // 产生0-36间的随机整数(要求各元素值不等) while((j=L.Find(x))!=-1); // 在集合中找x, 找不到则脱离循环 L.insert(L.size(),x); // 插入表尾 cout<<x<<" "; // 输出x ( 集合元素边产生边输出) } }

  25. void SetUnion(List<int>&La,List<int>&Lb) // 将La表和Lb表所表示的集合做"并",存入La表,Lb表被清空。 {int i,k,b; for(i=Lb.size(); i>0; i--) //从Lb表中逐次删除素尾元素(不必移动元素) { Lb.remove(i-1,b); //调用删除算法,被删元素存入b k=La.Find(b); // 在La表中查找b if(k==-1) // La表中找不到元素b La.insert(La.size(), b); // 插入至la表尾 } //end_for } void visit(int &i) { cout<<i<<' '; }

  26. Simply Linked Implementation template <class Node_entry> struct Node // Node declaration: { Node_entry entry; Node<Node_entry> *next; Node( ); // constructors Node(Node_entry, Node<Node_entry> *link=NULL); // constructors }; template <class List_entry>class List // List declaration: { public: // Specifications for the methods of the list ADT go here. // The following methods replace compiler-generated defaults.

  27. ~List( ); List(const List<List_entry> &copy); void operator=(const List<List_entry> &copy); protected: // Data members for the linked list implementation now follow. int count; Node<List_entry> *head; // The following auxiliary function is used to locate list positions Node<List_entry> *set_position(int position) const; };

  28. Actions on a Linked List

  29. Finding a List Position ◆Function set position takes an integer parameter position and returns a pointer to the corresponding node of the list. ◆Declare the visibility of set position as protected, since set position returns a pointer to, and therefore gives access to, a Node in the List. To maintain an encapsulated data structure, we must restrict the visibility of set position. Protected visibility ensures that it is only available as a tool for constructing other methods of the List. ◆ To construct set position, we start at the beginning of the List and traverse it until we reach the desired node:

  30. template <class List_entry> Node<List_entry> *List<List_entry>::set_position(int position) const /* Pre: position is a valid position in the List ;0 ≤ position<count . Post: Returns a pointer to the Node in position . */ { Node<List_entry> *q = head; for (int i=0; i<position; i++) q=q->next; return q; } ◆If all nodes are equally likely, then, on average, the set position function must move halfway through the List to find a given position. Hence, on average, its time requirement is approximately proportional to n, the size of the List.

  31. Insertion Method template <class List_entry> Error_code List<List_entry> :: insert(int position, const List_entry &x) /* Post: If the List is not full and 0 ≤ position ≤ n , where n is the number of entries in the List, the function succeeds: Any entry formerly at position and all later entries have their position numbers increased by 1, and x is inserted at position of the List. Else: The function fails with a diagnostic error_code. */ { if (position < 0 || position > count) return range_error; Node<List_entry> *new node, *previous, *following; if (position > 0) { previous = set position(position . 1); following = previous->next; } else following = head;

  32. new_node = new Node<List_entry>(x, following); if(new_node==NULL)return overflow; if (position==0) head = new_node; else previous->next = new_node; count++; return success; } Insert to Firsr entry

  33. 为了避免插入位置不同带来的处理方法的不一致,可以在第一个元素(“首元结点”)前,虚设一个结点称之为“头结点”;这样“头指针”指向“头结点”,如下图所示:为了避免插入位置不同带来的处理方法的不一致,可以在第一个元素(“首元结点”)前,虚设一个结点称之为“头结点”;这样“头指针”指向“头结点”,如下图所示:

  34. In processing a linked List with n entries:  clear, insert, remove, retrieve, and replace require time approximately proportional to n.  List, empty, full, and size operate in constant time. Variation: Keeping the Current Position ◆Suppose an application processes list entries in order or refers to the same entry several times before processing another entry. ◆Remember the last-used position in the list and, if the next operation refers to the same or a later position, start tracing through the list from this last-used position.

  35. ◆Note that this will not speed up every application using lists. ◆The method retrieve is defined as const, but its implementation will need to alter the last-used position of a List. To enable this, we use the mutable qualifier. Mutable data members of a class can be changed, even by constant methods. template <class List_entry>class List {public: // Add specifications for the methods of the list ADT. // Add methods to replace the compiler-generated defaults. protected: // Data members for the linked-list implementation with // current position follow:

  36. int count; mutable int current position; Node<List_entry> *head; mutable Node<List_entry> *current; // Auxiliary function to locate list positions follows: void set_position(int position) const; }; ◆All the new class members have protected visibility, so, from the perspective of a client, the class looks exactly like the earlier implementation. ◆The current position is now a member of the class List, so there is no longer a need for set position to return a pointer; instead,the function simply resets the pointer current directly within the List.

  37. template <class List_entry> void List<List_entry> :: set_position(int position) const /* Pre: position is a valid position in the List : 0<=position < count . Post: The current Node pointer references the Node at position . */ { if (position < current_position) // must start over at head of list { current_position = 0; current = head; } for (; current_position != position; current_position++) current = current->next; } ◆For repeated references to the same position, neither the body of the if statement nor the body of the for statement will be executed, and hence the function will take almost no time.

  38. ◆If we move forward only one position, the body of the for statement will be executed only once, so again the function will be very fast. ◆If it is necessary to move backwards through the List, then the function operates in almost the same way as the version of set position used in the previous implementation. 下面将Simply (single) Linked类的声明部分给出,实现及测试演示给大家(源代码可以复制给大家) 。

  39. #include <iostream.h> enum Error_code{ success, fail, range_error }; template <class Node_entry> struct Node // Node declaration { Node_entry entry; Node<Node_entry> *next; Node( ){ next=NULL; } Node(Node_entry data, Node<Node_entry> *link=NULL) { entry=data; next=link; } }; template <class List_entry> class List // Single lined list declaration { public: List(){ count=0; head = NULL; } // constructor List(const List<List_entry> &); // copy constructor ~List(); // destructor

  40. List& operator=(const List<List_entry>&); // List:overloaded assignment"=" bool empty() const // Judge whether isEmpty? { return count==0; } bool full()const; // Judge whether isFull? int size()const // Compute the length { return count; } void clear(); // to clear the List: become empty Error_code retrieve(int position, List_entry &x)const; Error_code replace(int position, const List_entry &x); Error_code remove(int position, List_entry &x); Error_code insert(int position, const List_entry &x); int find(const List_entry &x); /* search List entry x,return -1 if not find, otherwise return position of x */ void traverse(void (*visit)(List_entry &));

  41. protected: Node<List_entry> *head; //pointer: point to first node int count; //number of List_entry Node<List_entry> *set_position(int position) const; }; 注 Simply (single) Linked类的文件名如下: 声明及实现:SLList.h 测试程序: exp_slink.cpp Doubly Linked Lists

  42. Node definition: template <class Node_entry> struct Node { // data members Node_entry entry; Node<Node_entry> *next; Node<Node_entry> *back; // constructors Node( ); Node(Node_entry, Node<Node_entry> *link_back = NULL, Node<Node_entry> *link_next = NULL); };

  43. List definition: template <class List_entry> class List { public: // Add specifications for methods of the list ADT. // Add methods to replace compiler generated defaults. protected: // Data members for the doubly-linked list implementation follow: int count; mutable int current_position; mutable Node<List_entry> *current; // The auxiliary function to locate list positions follows: void set_position(int position) const; };

  44. ◆We can move either direction through the List while keeping only one pointer, current, into the List. ◆We do not need pointers to the head or the tail of the List, since they can be found by tracing back or forth from any given node. ◆To find any position in the doubly linked list, we rst decide whether to move forward or backward from the current position,and then we do a partial traversal of the list until we reach the desired position.

  45. template <class List entry> void List<List entry> :: set_position(int position) const /* Pre: position is a valid position in the List : 0 ≤position < count . Post: The current Node pointer references the Node at position . */ { if (current_position <= position) for ( ; current_position != position; current_position++) current = current->next; else for ( ; current_position != position; current_position--) current = current->back; } ◆The cost of a doubly linked list is the extra space required in each Node for a second link, usually trivial in comparison to the space for the information member entry.

  46. Insertion into a Doubly Linked List template <class List entry>Error code List<List entry> :: insert(int position, const List entry &x) /* Post:If the List is not full and 0 ≤position ≤n; where n is the number of entries in the List , the function succeeds: Any entry formerly at position and all later entries have their position numbers increased by1 and x is inserted at position of the List . Else: the function fails with a diagnostic error code. */ { Node<List entry> *new node, *following, *preceding; if (position < 0 || position > count) return range_error;

  47. if (position == 0) { if (count == 0) following = NULL; else { set_position(0); following = current; } preceding = NULL; } else { set_position(position - 1); preceding = current; following = preceding->next; } new_node = new Node<List entry>(x, preceding, following); if (new node == NULL) return overflow; if (preceding != NULL) preceding->next = new_node; if (following != NULL) following->back = new_node; current = new_node; current_position = position; count++; return success; }

  48. 下面将Doubly Linked List类的声明部分给出, 实现及测试演示给大家(源代码可以复制给大家) 。 注 文件名如下: 声明及实现:DLList.h 测试程序: exp_dlink.cpp

  49. 声明双向链表的结点结构 # include <iostream.h> enum Error_code{ success, fail, range_error }; template <class Node_entry> // Node declaration struct Node {// data members Node_entry entry; Node<Node_entry> *next; Node<Node_entry> *back; // constructors Node(); Node( Node_entry, Node<Node_entry> *link_back = NULL, Node<Node_entry> *link_next = NULL); }; 结点的数据域 其类型为模板 Node_entry 指向下一结点的指针 指向前一结点的指针 将next和back 置为“空”的 constructor1 next和back缺省值 为“空”(数据域及 指针均被初始化) 的constructor2

  50. Implementation constructor1 Implementation constructor2 template <class List_entry> Node<List_entry>::Node() { next = back = NULL; } template <class List_entry> Node<List_entry>:: Node ( List_entry data, Node<List_entry> *link_back,Node<List_entry> *link_next ) { entry = data; back = link_back; next = link_next; } 以双向链表的数据项 做为结点的数据域