1 / 90

单链表 循环链表 多项式及其相加 双向链表 稀疏矩阵

第三章 链表. 单链表 循环链表 多项式及其相加 双向链表 稀疏矩阵. 一、单链表. 线性表的链式表示. 顺序表的优点是可以随机选取表中元素 缺点是插入删除操作复杂。 用指针将互不相连的内存结点串成的 线性表叫 线性链表 。 结点 node 由一个数据元素域,一个或几个 指针域组成。 单链表 的结点只有一个指针域。. 几个结点,前一个结点的指针,指向后一个结点,就连接成一个 线性链表 。. 线性链表 的优点则是插入,删除快捷,缺点是选取复杂。. #include <stdlib.h〉 #include <iostream.h>

zuzana
Télécharger la présentation

单链表 循环链表 多项式及其相加 双向链表 稀疏矩阵

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第三章 链表 • 单链表 • 循环链表 • 多项式及其相加 • 双向链表 • 稀疏矩阵

  2. 一、单链表

  3. 线性表的链式表示 顺序表的优点是可以随机选取表中元素 缺点是插入删除操作复杂。 用指针将互不相连的内存结点串成的 线性表叫线性链表。 结点 node由一个数据元素域,一个或几个 指针域组成。单链表的结点只有一个指针域。

  4. 几个结点,前一个结点的指针,指向后一个结点,就连接成一个线性链表。几个结点,前一个结点的指针,指向后一个结点,就连接成一个线性链表。 线性链表的优点则是插入,删除快捷,缺点是选取复杂。

  5. #include <stdlib.h〉 #include <iostream.h> template <class T> class Node { Node<T> *next; //next 是下一个结点的地址 public: T data; // the data is public Node(const T& item, Node<T>* ptrnext=NULL); // list modification methods void InsertAfter(Node<T> *p); Node<T> * DeleteAfter(void); // obtain the address of the next node Node<T> *NextNode(void) const; }; 1. 结点类的定义

  6. // constructor. initialize data and // pointer members template <class T> Node<T>::Node(const T& item, Node<T>* ptrnext) : data(item), next(ptrnext)) { }

  7. // return value of private member next template <class T> Node<T>* Node<T>::NextNode(void) const { return next; }

  8. // insert a node p after the current one template <class T> void Node<T>::InsertAfter(Node<T> *p) { // p points to successor of the current // node, and current node points to p. p->next = next; next = p; }

  9. // delete the node following current and return its address template <class T> Node<T>* Node<T>::DeleteAfter(void) { // save address of node to be deleted Node<T>* tempPtr = next; // if there isn't a successor, return NULL if (next == NULL) return NULL; // current node points to successor of tempPtr. next = tempPtr->next; // return the pointer to the unlinked node return tempPtr; }

  10. 2.人工建立一个链表 void main(void) { Node<char>*a,*b,*c; a=new Node<char>('a'); b=new Node<char>('b'); c=new Node<char>('c'); Node<char>*head,*p; head=new Node<char>(' '); p=head; head->InsertAfter(a); head->InsertAfter(b); head->InsertAfter(c); while(p!=NULL) { cout << p->data<<" "; p=p->NextNode( ); } } • 测试结果:打印 c b a

  11. 3. 定义线性链表的一些操作 #include "node.h" // allocate a node with data member item and pointer nextPtr template <class T> Node<T>*GetNode(constT&item,Node<T>*nextPtr = NULL) { Node<T> *newNode; // allocate memory while passing item and NextPtr to // constructor. terminate program if allocation fails newNode = new Node<T>(item, nextPtr); if (newNode == NULL) { cerr << "Memory allocation failure!" << endl; exit(1); } return newNode; }

  12. enum AppendNewline {noNewline, addNewline}; template <class T> // print a linked list void PrintList (Node<T> *head, AppendNewline addnl = noNewline ) { // currPtr chains through the list, starting at head Node<T> *currPtr = head; // print the current node's data until end of list while(currPtr != NULL) { // output newline if addl == addNewline if(addnl == addNewline) cout << currPtr->data << endl; else cout << currPtr->data << " "; // move to next node currPtr = currPtr->NextNode( ); } }

  13. // find an item in a linked list head; return TRUE and // value of previous pointer if found; otherwise return FALSE template <class T> int Find(Node<T> *head, T& item, Node<T>* &prevPtr) { Node<T> *currPtr = head; // begin traversal at first node prevPtr = NULL; // cycle through the list until end of list while(currPtr != NULL) { if (currPtr->data == item) {item = currPtr->data; return1;} prevPtr = currPtr; currPtr = currPtr->NextNode( );} return 0; // failed to locate item }

  14. // insert item at the front of list template <class T> void InsertFront(Node<T>* & head, Titem) { // allocate new node so it points to original list head // update the list head head = GetNode(item,head); }

  15. // find rear of the list and append item template <class T> void InsertRear(Node<T>* & head, const T& item) { Node<T> *newNode, *currPtr = head; if (currPtr == NULL) // if list is empty, insert item at the front InsertFront(head,item); else { // find the node whose pointer is NULL while(currPtr->NextNode( ) != NULL) currPtr = currPtr->NextNode( ); // allocate node and insert at rear (after currPtr) newNode = GetNode(item); currPtr->InsertAfter(newNode); } }

  16. // delete the first node of the list template <class T> void DeleteFront(Node<T>* & head) { // save the address of node to be deleted Node<T> *p = head; // make sure list is not empty if (head != NULL) { // move head to second node and delete original head = head->NextNode( ); delete p; } }

  17. // delete the first occurrence of key in the list template <class T> void Delete (Node<T>* & head, T key) { Node<T> *currPtr = head, *prevPtr = NULL; if (currPtr == NULL) return; while (currPtr != NULL && currPtr->data != key) { prevPtr = currPtr; currPtr = currPtr->NextNode( ); } if (currPtr != NULL) { if(prevPtr == NULL) head = head->NextNode(); else prevPtr->DeleteAfter(); delete currPtr; } }

  18. // insert item into the ordered list template <class T> void InsertOrder(Node<T>* & head, Titem) { Node<T> *currPtr, *prevPtr, *newNode; prevPtr = NULL; currPtr = head; while (currPtr != NULL) { if (item < currPtr->data) break; prevPtr = currPtr; currPtr = currPtr->NextNode( ); } if (prevPtr == NULL) InsertFront(head,item); else { newNode = GetNode(item); prevPtr->InsertAfter(newNode); } }

  19. // delete all the nodes in the linked list template <classT> void ClearList(Node<T> * &head) { Node<T> *currPtr, *nextPtr; currPtr = head; while(currPtr != NULL) { nextPtr = currPtr->NextNode( ); delete currPtr; currPtr = nextPtr; } head = NULL; }

  20. 链表插入排序 #include <iostream.h> #pragma hdrstop #include "node.h" #include "nodelib.h"

  21. template <class T>void LinkSort(T a[], int n) { Node<T> *ordlist = NULL, *currPtr; int i; for (i=0;i < n;i++)InsertOrder(ordlist, a[i]); currPtr = ordlist; i = 0; while(currPtr != NULL) { a[i++] = currPtr->data; currPtr = currPtr->NextNode( ); } ClearList(ordlist); }

  22. // scan the array and print its elements void PrintArray(int a[], int n) { for(int i=0;i < n;i++) cout << a[i] << " "; }

  23. /*void main(void) { // initialized array with 10 integer values int A[10] = {82,65,74,95,60,28,5,3,33,55}; LinkSort(A,10); // sort the array cout << "Sorted array: "; PrintArray(A,10); // print the array cout << endl; } */ #endif // NODE_LIBRARY

  24. 链表的游标类 (Iterator) • 游标类主要用于单链表的搜索。 • 游标类的定义原则: • Iterator类是List类和ListNode类的友元类。 • Iterator对象引用已有的List类对象。 • Iterator类有一数据成员current,记录对单链表最近处理到哪一个结点。 • Iterator类提供若干测试和搜索操作

  25. 表示链表的三个类的模板定义 enum Boolean { False, True }; template <class Type> class List; template <class Type> class ListIterator; template <class Type> class ListNode { //表结点 friend class List <Type>; friend class ListIterator <Type>; public: ……… private: Type data; ListNode<Type> *link; };

  26. template <class Type> classList {//链表类 public: ……… private: ListNode<Type>*first, *last; }; template <class Type> class ListIterator { private: constList<Type>& list;//引用已有链表 ListNode<Type> *current;//当前结点指针public: ListNode<Type> *listfirst; ?

  27. ListIterator ( const List<Type>& l ) : list ( l ), current ( l.first){ } //构造函数: 引用链表l, 表头为当前结点 ListNode<Type> * Firster ( ) { current = list.first; return current; } //当前指针置于表头, 返回表头结点地址 Boolean NotNull ( );//检查当前指针空否 Boolean NextNotNull ( ); //检查链表中下一结点是否非空 ListNode <Type> *First ( ); //返回第一个结点的地址 ListNode <Type>*Next ( ); //返回链表当前结点的下一个结点的地址 }

  28. 链表的游标类成员函数的实现 template <class Type> Boolean ListIterator<Type> :: NotNull( ) { //检查链表中当前元素是否非空 if ( current != NULL ) return True; else return False; } current current 情况 1 返回True情况 2 返回False

  29. template <class Type> Boolean ListIterator<Type> :: NextNotNull ( ) { //检查链表中下一元素是否非空 if ( current != NULL && current->link != NULL ) return True; else return False; } current current 情况 1 返回True情况 2 返回False

  30. template <class Type> ListNode<Type>* ListIterator<Type> :: First ( ) { //返回链表中第一个结点的地址 if ( list.first->link != NULL ) { current = list.first->link; return current; } else { current = NULL; return NULL; } } 链表中有表头结点 list.first current

  31. template <class Type> ListNode<Type>* ListIterator<Type> :: Next ( ) { //返回链表中当前结点的下一个结点的地址 if ( current != NULL && current->link != NULL ) { current = current->link; return current; } else { current = NULL; return NULL; } } current current

  32. 利用游标类 (iterator) 计算元素的和 int sum ( const List<int>&L ) { ListIterator<int> li (L); //定义游标对象, current 指向li.first if (li. First( ) ==NULL) return 0; //链表为空时返回0 int retval =current->data;//第一个元素 while ( li.nextNotNull ( ) )//链表未扫描完 retval += li.Next( )->data;//累加 return retval; }

  33. 静态链表结构

  34. 静态链表定义 const int MaxSize = 100;//静态链表大小 template <class Type> class StaticList; template <class Type> class SListNode { friend class StaticList<Type>; Type data;//结点数据 int link;//结点链接指针 } template <class Type> class StaticList { SListNode<Type> Nodes[MaxSize]; int newptr; //当前可分配空间首地址 }

  35. 将链表空间初始化 template <class Type> void StaticList<Type> :: InitList ( ) { Nodes[0].link = -1; newptr = 1; //当前可分配空间从 1 开始建 //立带表头结点的空链表 for ( int i = 1; i < MaxSize-1; i++ ) Nodes[i].link = i+1;//构成空闲链接表 Nodes[MaxSize-1].link = -1; //链表收尾 }

  36. 在静态链表中查找具有给定值的结点 template <class Type> int StaticList<Type> :: Find ( Type x ) { int p = Nodes[0].link; //指针 p 指向链表第一个结点 while ( p != -1 ) if ( Nodes[p].data != x) p = Nodes[p].link; else break; //逐个结点检测查找具有给定值的结点 return p; }

  37. 在静态链表的表尾追加一个新结点 template <class Type> int StaticList<Type> :: Append ( Type x ) { if ( newptr == -1 ) return 0; //追加失败 int q = newptr; //分配结点 newptr = Nodes[newptr].link; Nodes[q].data = x; Nodes[q].link = -1; int p = 0; //查找表尾 while ( Nodes[p].link != -1 ) p = Nodes[p].link; Nodes[p].link = q; //追加 return 1; }

  38. 在静态链表中查找第i个结点 template <class Type> int StaticList<Type> :: Locate ( int i ) { if ( i < 0 ) return-1; //参数不合理 if ( i == 0 ) return 0; int j = 0, p = Nodes[0].link; while ( p != -1 && j < i ) { p = Nodes[p].link; j++; } //循链查找第 i号结点 return p; }

  39. 在静态链表第 i个结点处插入一个新结点 template <class Type> int StaticList<Type> :: Insert ( int i, Type x ) { int p = Locate ( i-1 ); if ( p == -1 ) return 0; //找不到结点 int q = newptr; //分配结点 newptr = Nodes[newptr].link; Nodes[q].data = x; Nodes[q].link = Nodes[p].link; //链入 Nodes[p].link = q; return 1; }

  40. 在静态链表中释放第 i 个结点 template <class Type> int StaticList<Type> :: Remove ( int i ) { int p = Locate ( i-1 ); if ( p == -1 ) return 0; //找不到结点 int q = Nodes[p].link; //第 i 号结点 Nodes[p].link = Nodes[q].link; Nodes[q].link = newptr; //释放 newptr = q; return 1; }

  41. 二、循环链表 (Circular List) • 循环链表是单链表的变形。 • 循环链表的最后一个结点的link指针不为 NULL,而是指向了表的前端。 • 为简化操作,在循环链表中往往加入表头结点。 • 循环链表的特点是:只要知道表中某一结点的地址,就可搜寻到所有其他结点的地址。

  42. first a0 a1 a2 an-1 • 循环链表的示例 • 带表头结点的循环链表 first a0 a1 an-1 (非空表) first (空表)

  43. 循环链表类的定义 template <class Type> class CircList; template <class Type> class CircListNode { friend class CircList <Type>; public: CircListNode ( Type d = 0, CircListNode<Type> *next = NULL ) : data ( d ), link ( next ) { } //构造函数private: Type data; //结点数据 CircListNode<Type> *link; //链接指针 }

  44. template <class Type> class CircList { private: CircListNode<Type> *first, *current, *last; //链表的表头指针、当前指针和表尾指针 public: CircList ( Type value ); ~CircList ( ); int Length ( ) const; Boolean IsEmpty ( ) { return first->link == first;} Boolean Find ( const Type & value );

  45. Type getData( ) const; void Firster ( ) { current = first; } Boolean First ( ); Boolean Next ( ); Boolean Prior ( ); void Insert ( const Type & value ); void Remove ( ); };

  46. 循环链表的搜索算法 31 48 15 57 first    搜索成功 搜索15 current current current first 31 48 15 57     current current current current current 搜索不成功 搜索25

  47. 循环链表的搜索算法 template <class Type> CircListNode<Type> * CircList<Type> :: Find ( Type value) { //在链表中从头搜索其数据值为value的结点 current = first->link; //检测指针current 指示第一个结点 while ( current != first && current->data != value ) current = current->link; return current; }

  48. 用循环链表求解约瑟夫问题 • 约瑟夫问题的提法 n个人围成一个圆圈,首先第 1 个人从 1 开始一个人一个人顺时针报数, 报到第m个人,令其出列。然后再从下一 个人开始,从 1 顺时针报数,报到第m 个人,再令其出列,…,如此下去, 直到圆圈中只剩一个人为止。此人即为优胜者。

  49. 例如 n = 8 m = 3

  50. 约瑟夫问题的解法 #include <iostream.h> #include “CircList.h” Template<Type> void CircList<Type> :: Josephus ( int n, int m ) { First ( ); for ( int i = 0; i < n-1; i++ ) {//执行n-1次 for ( int j = 0; j < m-1; j++ ) Next ( ); cout << “出列的人是” << getData ( ) << endl;//数m-1个人 Remove ( );//删去 }

More Related