当前位置:   article > 正文

数据结构--线性表_直接前驱和直接后继描述了结点之间的

直接前驱和直接后继描述了结点之间的

简述:

线性表是 n (≥0) 个数据元素的有限序列
记作L =(a1, a2, …, an),ai 是表中数据元素(也叫表项),n 是线性表的长度,L是表名。n=0是空表, 第1个表项叫表头(head),最后1个表项叫表尾(tail)。


原则上讲,线性表中元素的数据类型可以不相同。由于采用的存储结构不同,会对元素的数据类型有限制。为简单起见,假定各元素类型相同。

线性表特点
1.除第一个元素外,其他每一个元素有一个且仅有一个直接前驱。

2.除最后一个元素外,其他每一个元素有一个且仅有一个直接后继。

3.直接前驱和直接后继描述了结点之间的逻辑关系,即邻接关系,表示为<ai , ai+1> 。

一、顺序表

将线性表中元素相继存放在一个连续的存储空间中。可利用一维数组实现。
顺序表特点:
逻辑顺序与物理存储顺序一致,可随机访问。

具体实现:

  1. #include<iostream>
  2. using namespace std;
  3. const int kDefaultSize = 100;
  4. //线性表中存放不同的数据类型,可以用union实现
  5. //union T
  6. //{
  7. // int val;
  8. // char ch;
  9. // float dir;
  10. // T* link;
  11. //};
  12. template <class T>
  13. class SeqList {
  14. public:
  15. SeqList(int size=kDefaultSize);
  16. ~Seqlist();
  17. SeqList(SeqList<T>& L);//拷贝构造
  18. SeqList<T>& operator=(SeqList<T>& L);//重载运算符=
  19. bool GetData(int i, T& x) const;
  20. void SetData(int i, T& x);
  21. bool IsEmpty()const;
  22. bool IsFull()const;
  23. int Size() const;//表中最大容纳的元素的个数
  24. int Length() const;//表长度
  25. void Sort();
  26. int Locate(int i) const;//定位第i个元素,返回表项序号
  27. bool Insert(int i, const T& x);//在第i个元素位置插入数据x
  28. bool Remove(int i, T& x);//删除第i个元素,通过x返回该元素的值
  29. int Search(const T& x) const;
  30. //顺序表的静态存储
  31. // T data[kDefaultSize];
  32. // int n;//表示当前元素个数
  33. //顺序表的动态存储
  34. private:
  35. T* data;
  36. int n;
  37. int MAXSIZE;//表示最大能够容纳的元素个数
  38. void resize(int newSize);//改变数组空间的大小
  39. };
  40. template <class T>
  41. SeqList<T>::SeqList(int size)
  42. {
  43. if (size > 0)
  44. {
  45. maxSize = size;
  46. n = 0;
  47. data = new T[maxSize];
  48. if (data = nullptr)
  49. {
  50. cerr << "存储分配错误!" << endl;
  51. exit(1);
  52. }
  53. }
  54. }
  55. template <class T>
  56. bool SeqList<T>::IsEmpty()const
  57. {
  58. return n == 0 ? true : false;
  59. }
  60. template <class T>
  61. bool SeqList<T>::IsFull()const
  62. {
  63. return n == MAXSIZE ? true : false;
  64. }
  65. template <class T>
  66. int SeqList<T>::Size()const
  67. {
  68. return MAXSIZE;
  69. }
  70. template <class T>
  71. int SeqList<T>::Length()const
  72. {
  73. return n;
  74. }
  75. template <class T>
  76. int SeqList<T>::Locate(int i)const
  77. {
  78. if (i >= 1 && i <= n)
  79. {
  80. return i;
  81. }
  82. else
  83. {
  84. return 0;
  85. }
  86. }
  87. template <class T>
  88. bool SeqList<T>::GetData(int i,T&x)const
  89. {
  90. if (i >= 1 && i <= n)
  91. {
  92. x = data[i - 1];
  93. return true;
  94. }
  95. return false;
  96. }
  97. template <class T>
  98. void SeqList<T>::SetData(int i, T& x)
  99. {
  100. if (i >= 1 && i <= n)
  101. {
  102. data[i - 1] = x;
  103. }
  104. }
  105. template <class T>
  106. int SeqList<T>::Search(const T& x)const
  107. {
  108. for (int i = 0; i < n; i++)
  109. {
  110. if(data[i]==x)
  111. return (i+1)
  112. }
  113. return 0;
  114. }
  115. template <class T>
  116. bool SeqList<T>::Insert(int i,const T& x)
  117. {
  118. if (n == MAXSIZE) return false;
  119. if (i<1 || i>n + 1) return false;
  120. if (i < n)
  121. {
  122. for (int j = n; j>=i; j--)
  123. {
  124. data[j] = data[j - 1];
  125. }
  126. }
  127. data[i - 1] = x;
  128. n++;
  129. return true;
  130. }
  131. template <class T>
  132. bool SeqList<T>::Remove(int i, T& x)
  133. {
  134. if (n==0) return false;
  135. if (i<1 || i>n) return false;
  136. x= data[i - 1];
  137. if (i < n)
  138. {
  139. for (int j = i; j<n; j++)
  140. {
  141. data[j-1] = data[j];
  142. }
  143. }
  144. n--;
  145. return true;
  146. }
  147. template <class T>
  148. SeqList<T>::SeqList(SeqList<T>& L) {
  149. maxSize = L.Size();
  150. n = L.Length();
  151. data = new T[maxSize];
  152. if (data == nullptr) {
  153. cerr << “存储分配错误” << endl; exit(1);
  154. }
  155. T value;
  156. for (int i = 1; i <= n; i++) {
  157. L.GetData(i, value);
  158. data[i - 1] = value;
  159. }
  160. }
  161. template <class T>
  162. SeqList<T>& SeqList<T>:: operator=(SeqList<T>& L)
  163. {
  164. if (this == &L) // 自复制,返回自身
  165. return *this;
  166. delete[] data;
  167. maxSize = L.Size();
  168. n = L.Length();
  169. data = new T[maxSize]; // 动态空间分配
  170. if (data == nullptr) {
  171. cerr << “存储分配错误” << endl;
  172. exit(1);
  173. }
  174. T value;
  175. for (int i = 1; i <= n; i++) {
  176. L.GetData(i, value); // 获取L中第i个元素的值
  177. data[i - 1] = value; // 将该值赋给data数组的第i个元素
  178. }
  179. return *this;
  180. }

二、单链表

单链表是包含0个或多个元素的线性结构,其中每个元素(也称为结点node)包含两个域:数据域和链域。
数据域data:存储线性表的一个元素信息,其数据类型由应用问题决定。
链域:存储一个指针,指向下一个结点的存储地址。表示元素ai与ai+1之间的逻辑关系,即直接后继的存储地址。

first指针为空指针nullptr时,表示该链表当前有0个元素。
表尾没有直接后继,其链域设置为空。

特点:

结点之间可以连续,可以不连续存储。
结点的逻辑顺序与物理顺序可以不一致。
表的长度可以很方便的进行扩充。

具体实现过程如下:

  1. #include<iostream>
  2. using namespace std;
  3. //不带头结点的链表
  4. template<class T> struct ListNode
  5. {
  6. T data;
  7. ListNode<T>* next;
  8. LinkNode<const T& item, LinkNode<T>* ptr = NULL>;
  9. LinkNode(LinkNode<T>* ptr = NULL);
  10. };
  11. template <class T>
  12. class List
  13. {
  14. public:
  15. List();
  16. List(const List<T>& L);//拷贝构造函数
  17. List<T>& operator=(const List<T>& L);
  18. ~List();
  19. void InputFront(const T& elem); // 在表头插入元素
  20. void InputRear(const T& elem); // 在表尾插入元素
  21. bool Insert(int i, const T& x); // 在第i个位置插入元素
  22. bool Remove(int i, T& x); // 删除第i个位置的元素
  23. ListNode<T>* Search(const T& x); // 查找元素x
  24. ListNode<T>* Locate(int i); // 返回第i个结点的位置
  25. bool GetData(int i, T& x) const;// 获取第i个位置的元素
  26. void SetData(int i, const T& x); // 设置第i个位置的元素
  27. void MakeEmpty(); // 清空表
  28. void CopyList(const List<T>& L); // 拷贝表
  29. int Length() const; // 获取表长度
  30. bool IsEmpty() const; // 判断表是否为空
  31. bool IsFull() const; // 判断表是否为满
  32. void Sort(); // 对表进行排序
  33. friend ostream& operator<<(
  34. ostream& out, const List<T>& L); //重载输出运算符
  35. friend istream& operator>>(
  36. istream& in, List<T>& L); //重载输入运算符
  37. void travel_list();//遍历链表
  38. private:
  39. ListNode<T>* first;
  40. };
  41. template <class T>
  42. void List<T>::travel_list()
  43. {
  44. for (ListNode<T>* iter = first; iter != nullptr; iter = iter->next)
  45. {
  46. cout << iter->data << " ";
  47. }
  48. /*另一种遍历方法:
  49. LinkNode<T>* iter = first;
  50. while (iter != NULL) {
  51. cout << iter->data << " ";
  52. iter = iter->next;
  53. }*/
  54. }
  55. template <class T>
  56. int List<T>::Length() const {
  57. int len = 0;
  58. ListNode<T>* iter = first;
  59. while (iter != nullptr) {
  60. len++;
  61. iter = iter->next;
  62. }
  63. return len;
  64. }
  65. template <class T>
  66. ListNode<T>* List<T>:: Search (const T&x){
  67. ListNode<T>* iter = first;
  68. while (iter != nullptr) {
  69. if (iter->data ==x )
  70. {
  71. return iter;
  72. }
  73. iter = iter->next;
  74. }
  75. return iter;
  76. /*另外一种查找方式
  77. LinkNode<T>* Search(const T & x) {
  78. LinkNode<T>* iter = first;
  79. while (iter != nullptr && iter->data != x) {
  80. iter = iter->next;
  81. }
  82. return iter;
  83. }*/
  84. }
  85. template<class T>
  86. ListNode<T>* List<T>::Locate(int i)
  87. {
  88. if (i<0 || i>length())
  89. {
  90. return nullptr;
  91. }
  92. ListNode<T>* iter = first;
  93. int j = 1; // 记录当前结点的位置
  94. while (iter != nullptr && j < i) { // 当前结点非空且位置小于i
  95. iter = iter->next;
  96. j++;
  97. }
  98. return iter; // 返回第i个结点的位置
  99. }
  100. template<class T>
  101. void List<T>::SetData(int i,const T&x)
  102. {
  103. ListNode<T>* p = Locate(i);
  104. if (p != nullptr)
  105. {
  106. p->data = x;
  107. }
  108. }
  109. template <class T> // 获取第i个位置的元素
  110. bool List<T>::GetData(int i, T& x) const {
  111. ListNode<T>* p = Locate(i);
  112. if (p != nullptr) {
  113. x = p->data;
  114. return true;
  115. }
  116. return false;
  117. }
  118. template <class T>
  119. void List<T>::InputFront(const T& elem)
  120. {
  121. ListNode<T>* newNode = new ListNode<T>(elem);
  122. if (newNode == nullptr)
  123. return;
  124. newNode->next = first;
  125. first = newNode;
  126. }
  127. template <class T>
  128. void List<T>::InputRear(const T& elem)
  129. {
  130. ListNode<T>* newNode = new ListNode<T>(elem);
  131. if (newNode == nullptr)
  132. return;
  133. if (first == nullptr)
  134. {
  135. first = newNode;
  136. }
  137. else
  138. {
  139. ListNode<T>* rear = first;
  140. while (rear->next != nullptr)
  141. {
  142. rear = rear->next;
  143. }
  144. rear->next = newNode;
  145. }
  146. }
  147. template<class T>
  148. bool List<T>::Insert(int i, const T& x)//让第i个结点的值,变成插入的x
  149. {
  150. if (i<1 || i>n)
  151. return false;
  152. else {
  153. if (first->next=NULL)//表头节点没有直接前驱
  154. {
  155. InputFront(x);
  156. return true;
  157. }
  158. else {
  159. pre = first;
  160. for (int j = 1; j < i - 1; j++)
  161. {
  162. if (pre = nullptr) break;
  163. pre = pre->next;
  164. }
  165. /*定位当前位置的前驱结点pre
  166. listNodeM<T>* pre = locate(i - 1);*/
  167. if (pre = nullptr)
  168. {
  169. ceer << "无效的插入位置" << endl;
  170. return false;
  171. }
  172. else
  173. {
  174. newNode = new ListNode<T>(x);
  175. newNode->next = pre->next;
  176. pre->next;
  177. return true;
  178. }
  179. }
  180. }
  181. }
  182. template<class T>
  183. bool List<T>::Remove(int i, T& x)
  184. {
  185. ListNode<T>* del;
  186. ListNode<T>* pre = Locate(i - 1); // 定位当前位置的前驱节点pre
  187. if (pre == nullptr || pre->next == nullptr) // 空表或者表链太短
  188. return false;
  189. del = pre->next; // 当前位置
  190. pre->next = del->next;
  191. x = del->data; //保存删除结点的数据
  192. delete del;
  193. return true;
  194. }
  195. template<class T>
  196. void List<T>::MakeEmpty()
  197. {
  198. ListNode<T>* pnd = NULL;
  199. while (first != NULL)
  200. {
  201. pnd = first;
  202. first = first->next;
  203. delete pnd;
  204. }
  205. }
  206. template<class T>
  207. List<T>::~List()
  208. {
  209. MakeEmpty();
  210. }
  211. template<class T>
  212. void List<T>::CopyList(const List<T>& L)
  213. {
  214. if (L.first == NULL)
  215. return;
  216. ListNode<T>* newNode = new ListNode<T>(L.first->data);
  217. first = newNode;
  218. iter = L.first->next;
  219. rear = newNode;
  220. while (iter)
  221. {
  222. newNode= new LinkNode<T>(iter->data);
  223. rear->next = newNode;
  224. iter = iter->next;
  225. rear = rear->next;
  226. }
  227. }
  228. template<class T>
  229. List<T>::List(const List<T>& L)
  230. {
  231. first = nullptr;
  232. CopyList(L);
  233. }
  234. template<class T>
  235. List<T>& List<T>::operator=(const List<T>& L)
  236. {
  237. //首先判断是否是自复制,如果不是,调用CopyList函数完成链表的复制。
  238. if (this == &L)
  239. return *this;
  240. MakeEmpty();
  241. CopyList(L);
  242. return *this;
  243. }

三、循环链表

循环链表(circular list)是另一种形式的表示线性表的链表,它的结点结构与单链表相同,与单链表不同的是链表中表尾结点的next域中不是NULL,而是存放了一个指向链表开始结点的指针。

链表表尾的特点不再是其next域指向NULL,而是其next区域指向表头结点。

在表头位置插入或删除结点,不仅需要修改first指针指向,也需要修改表尾结点next域的指向。

实现过程及举例

  1. #include<iostream>
  2. using namespace std;
  3. template<class T>
  4. struct CircLinkNode
  5. {
  6. T data;
  7. CircLinkNode* next;
  8. CircLinkNode(const T& item, CircLinkNode<T>* ptr = NULL)
  9. {
  10. data = item;
  11. next = ptr;
  12. }
  13. CircLinkNode(CircLinkNode<T>* ptr = NULL)
  14. {
  15. next = ptr;
  16. }
  17. };
  18. template <class T> //链表类定义
  19. class CircList {
  20. private:
  21. CircLinkNode<T>* first, * last; //头指针, 尾指针
  22. public:
  23. CircList(const T& x); //构造函数
  24. CircList(const CircList<T>& L); //复制构造函数
  25. CircList<T> operator=(const CircList<T>& L); // 赋值运算符函数
  26. ~CircList(); //析构函数
  27. bool Insert(int i, const T& x); //插入
  28. bool Remove(int i, T& x); //删除
  29. CircLinkNode<T>* Search(const T& x); //搜索
  30. CircLinkNode<T>* Locate(int i); //定位
  31. T* getData(int i); //提取
  32. void setData(int i, T x); //修改
  33. int Length() const; //计算链表长度
  34. bool IsEmpty();//判表空否
  35. CircLinkNode<T>* getHead() const; //返回表头结点地址
  36. void setHead(CircLinkNode<T>* p); //设置表头结点地址
  37. };
  38. //功能举例实现:
  39. template <class T>
  40. CircLinkNode<T>* CircList<T>::Search(const T& x)
  41. {
  42. //在链表中从头搜索其数据值为 x 的结点
  43. current = first->next;
  44. while (current != first && current->data != x)
  45. current = current->next;
  46. return current;
  47. }

四、双向循环链表

双向链表是指在前驱和后继方向都能游历(遍历)的线性链表。

双向链表通常采用带表头结点的循环链表形式。

具体实现:

  1. #include<iostream>
  2. using namespace std;
  3. template <class T>
  4. struct DblNode {
  5. T data;
  6. DblNode<T>* rLink, * lLink;
  7. DblNode(DblNode<T>* l = NULL, DblNode<T>* r = NULL) {
  8. lLink = l;
  9. rLink = r;
  10. }
  11. DblNode(T value, DblNode<T>* l = NULL, DblNode<T>* r = NULL) {
  12. data = value;
  13. lLink = l;
  14. rLink = r;
  15. }
  16. };
  17. template <class T>
  18. class DblList {
  19. private:
  20. DblNode<T>* first;
  21. public:
  22. DblList();
  23. DblList(const DblList<T>& L);
  24. DblList<T>& operator=(const DblList<T>& L);
  25. ~DblList();
  26. void MakeEmpty(); //清空
  27. void CopyList(); //复制链表
  28. DblNode<T>* GetFirst()const; //返回头结点
  29. DblNode<T>* Locate(int i, int d = 1); //判断第i个结点是否在链表中
  30. bool Insert(int i, const T& x, int d = 1);//在第i个位置插入结点
  31. bool Remove(int i, T& x, int d);//在第i个位置删除节点
  32. DblNode<T>* Search(const T& x, int d = 1);// 搜索x
  33. void SetData(int i, const T& x);// 设置第i个位置上的结点
  34. bool GetData(int, T& x); //返回第i位置上的结点
  35. bool IsEmpty(); //判空
  36. bool IsFull(); //判满
  37. friend istream& operator >> (istream& in, DblList<T>& dbl);
  38. friend ostream& operator << (ostream& out, DblList <T>& dbl);
  39. };

五、静态链表

为数组中每一个元素附加一个链接指针,就形成静态链表结构。

处理时可以不改变各元素的物理位置,只要重新链接就能改变这些元素的逻辑顺序。

它是利用数组定义的,在整个运算过程中存储空间的大小不会变化。

静态链表每个结点由两个数据成员构成:data域存储数据,next域存放链接指针。
所有结点形成一个结点数组。

下标0是表头结点,next是链域,下个结点的地址。

循环链表的表尾的链域next = 0,回到表头结点。

如果不是循环链表,表尾结点指针next = -1。

next指针是数组下标,因此是整数。

欢迎批评指正!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/650675
推荐阅读
相关标签
  

闽ICP备14008679号