• 数据结构实战开发教程(五)再论智能指针、循环链表的实现、双向链表的实现、双向循环链表的实现、Linux内核链表剖析


    二十七、再论智能指针(上)

    1、思考

    • 使用智能指针( SmartPointer )替换单链表( LinkList )中的原生指针是否可行?

    2、问题出在哪里?

    • SmartPointer的设计方案
      • 指针生命周期结束时主动释放堆空间
      • 一片堆空间最多只能由一个指针标识
      • 杜绝指针运算和指针比较

    3、新的设计方案

    是时候创建新的智能指针了!

    4、新的设计方案

    • Pointer智能指针的抽象父类(模板)
      • 纯虚析构函数virtual ~Pointer() = 0;
      • 重载operator -> ()
      • 重载operator * ()

    5、编程实验:智能指针的新方案

    Pointer.h

    SmartPointer.h

    6、To be continued

    二十八、再论智能指针(下)

    1、完成SharedPointer类的具体实现

     

    2、SharedPointer设计要点

    • 类模板
      • 通过计数机制( ref )标识堆内存
        • 堆内存被指向时:ref++
        • 指针被置空时:ref--
        • ref == 0 时:释放堆内存

    3、计数机制原理剖析

    4、SharedPointer类的声明

    5、智能指针的比较

    由于SharedPointer支持多个对象同时指向一片堆空间;因此,必须支持比较操作

    6、编程实验:智能指针的新成员

    SharedPointer.h

    1. #ifndef SHAREDPOINTER_H_
    2. #define SHAREDPOINTER_H_
    3. /*******************************************************************************
    4. * Include _Files *
    5. *******************************************************************************/
    6. #include <cstdlib>
    7. #include "Pointer.h"
    8. #include "Exception.h"
    9. /*******************************************************************************
    10. * Type Definition *
    11. *******************************************************************************/
    12. namespace DTLib
    13. {
    14. template < typename T >
    15. class SharedPointer : public Pointer<T>
    16. {
    17. protected:
    18. int* m_ref; // 计数机制成员指针
    19. // 获取当前的智能指针地址、计数变量地址、计数变量 +1
    20. void assign(const SharedPointer<T>& obj)
    21. {
    22. this->m_ref = obj.m_ref; // 获取共用的计数变量地址
    23. this->m_pointer = obj.m_pointer; // 获取共用的堆空间地址
    24. if( this->m_ref )
    25. {
    26. (*this->m_ref)++; // 计数变量 +1
    27. }
    28. }
    29. public:
    30. // 构造函数
    31. SharedPointer(T* p = NULL) : m_ref(NULL)
    32. {
    33. if( p )
    34. {
    35. this->m_ref = static_cast<int*>(std::malloc(sizeof(int))); // 申请计数变量堆空间
    36. if( this->m_ref )
    37. {
    38. *(this->m_ref) = 1; // 计数变量 +1
    39. this->m_pointer = p; // 获取p对应的堆空间
    40. }
    41. else
    42. {
    43. THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create SharedPointer object ...");
    44. }
    45. }
    46. }
    47. SharedPointer(const SharedPointer<T>& obj) : Pointer<T>(NULL)
    48. {
    49. assign(obj); // 获取当前的智能指针地址、计数变量地址、计数变量 +1
    50. }
    51. SharedPointer<T>& operator= (const SharedPointer<T>& obj)
    52. {
    53. if( this != &obj )
    54. {
    55. clear(); // 让当前的智能指针置空,计数变量 -1
    56. assign(obj); // 获取当前的智能指针地址、计数变量地址、计数变量 +1
    57. }
    58. return *this;
    59. }
    60. // 让当前的智能指针置空,计数变量 -1
    61. void clear()
    62. {
    63. T* toDel = this->m_pointer;
    64. int* ref = this->m_ref;
    65. this->m_pointer = NULL; // 智能指针指向的堆空间地址 置 NULL
    66. this->m_ref = NULL; // 智能指针指向的计数变量地址 置 NULL
    67. if( ref )
    68. {
    69. (*ref)--; // 计数变量 -1
    70. if( *ref == 0 ) // 计数变量为 0
    71. {
    72. free(ref); // 释放共用的计数变量的堆空间
    73. delete toDel; // 释放共用的堆空间
    74. }
    75. }
    76. }
    77. ~SharedPointer()
    78. {
    79. clear(); // 让当前的智能指针置空,计数变量 -1
    80. }
    81. };
    82. // 支持比较操作 智能指针地址 <==> 智能指针地址 <==> 类对象地址
    83. template < typename T >
    84. static bool operator == (const T* l, const SharedPointer<T>& r)
    85. {
    86. return (l == r.get());
    87. }
    88. template < typename T >
    89. static bool operator != (const T* l, const SharedPointer<T>& r)
    90. {
    91. return (l != r.get());
    92. }
    93. template < typename T >
    94. static bool operator == (const SharedPointer<T>& l, const T* r)
    95. {
    96. return (l.get() == r);
    97. }
    98. template < typename T >
    99. static bool operator != (const SharedPointer<T>& l, const T* r)
    100. {
    101. return (l.get() != r);
    102. }
    103. template < typename T >
    104. static bool operator == (const SharedPointer<T>& l, const SharedPointer<T>& r)
    105. {
    106. return (l.get() == r.get());
    107. }
    108. template < typename T >
    109. static bool operator != (const SharedPointer<T>& l, const SharedPointer<T>& r)
    110. {
    111. return !(l == r);
    112. }
    113. }
    114. #endif // SHAREDPOINTER_H_

    7、智能指针的使用军规

    • 只能用来指向堆空间中的单个变量(对象)
    • 不同类型的智能指针对象不能混合使用
    • 不要使用delete释放智能指针指向的堆空间

    8、小结

    • SharedPointer最大程度的模拟了原生指针的行为
    • 计数机制确保多个智能指针合法的指向同一片堆空间
    • 智能指针只能用于指向堆空间中的内存
    • 不同类型的智能指针不要混合使用
    • 堆对象的生命周期由智能指针进行管理

    二十九、循环链表的实现

    1、什么是循环链表?

    • 概念上
      • 任意数据元素都有一个前驱和一个后继
      • 所有的数据元素的关系构成一个逻辑上的环
    • 实现上
      • 循环链表是一种特殊的单链表
      • 尾结点的指针域保存了首结点的地址

    2、循环链表的逻辑构成

    3、循环链表的继承层次结构

    4、循环链表的实现思路

    • 通过模板定义CircleList类,继承自LinkList
    • 定义内部函数last_to_first(),用于将单链表首尾相连
    • 特殊处理:首元素的插入操作和删除操作
    • 重新实现:清空操作和遍历操作

    5、循环链表的实现要点

    • 插入位置为0时:
      • 头结点和尾结点均指向新结点
      • 新结点成为首结点插入链表
    • 删除位置为0时:
      • 头结点和尾结点指向位置为1的结点
      • 安全销毁首结点

    6、编程实验:循环链表的实现

    CircleList.h

    1. #ifndef CIRCLELIST_H_
    2. #define CIRCLELIST_H_
    3. /*******************************************************************************
    4. * Include _Files *
    5. *******************************************************************************/
    6. #include "LinkList.h"
    7. /*******************************************************************************
    8. * Type Definition *
    9. *******************************************************************************/
    10. namespace DTLib
    11. {
    12. template < typename T >
    13. class CircleList : public LinkList<T>
    14. {
    15. protected:
    16. typedef typename LinkList<T>::Node Node; // 使用typename的原因:编译器无法辨识标识符究竟是什么(是一个类型还是一个成员名称(静态数据成员或者静态函数))
    17. int mod(int i) const // 取余
    18. {
    19. return (this->m_length == 0) ? 0 : (i % this->m_length);
    20. }
    21. Node* last() const // 尾结点的指针
    22. {
    23. return this->position(this->m_length-1)->next;
    24. }
    25. void last_to_first() const // 将链表首尾相连
    26. {
    27. last()->next = this->m_header.next; // 尾结点指向首结点
    28. }
    29. public:
    30. /**********************************************************************
    31. * Function: insert()
    32. * Description: 插入新结点(函数重载)
    33. * Input: i 在位置i插入新结点(默认插在最后)
    34. * e 带插入结点的数据(value)
    35. * Output:
    36. * Return: bool 判断插入结点位置是否合法
    37. * Others: 异常 申请内存是否成功
    38. * Modify Date Version Author Modification
    39. * ------------------------------------------------------------
    40. * 2022/03/19 1.0 Create
    41. **********************************************************************/
    42. bool insert(const T& e)
    43. {
    44. return insert(this->m_length, e);
    45. }
    46. bool insert(int i, const T& e)
    47. {
    48. bool ret = true;
    49. i = i % (this->m_length + 1); // 取余
    50. ret = LinkList<T>::insert(i, e); // 调用父类的插入函数
    51. if( ret && (i == 0) ) // 处理特殊情况(首结点)
    52. {
    53. last_to_first(); // 将链表首尾相连
    54. }
    55. return ret;
    56. }
    57. /**********************************************************************
    58. * Function: remove()
    59. * Description: 删除结点
    60. * Input: i 在位置i删除结点
    61. * Output:
    62. * Return: bool 判断删除结点位置是否合法
    63. * Others:
    64. * Modify Date Version Author Modification
    65. * ------------------------------------------------------------
    66. * 2022/03/19 1.0 Create
    67. **********************************************************************/
    68. bool remove(int i)
    69. {
    70. bool ret = true;
    71. i = mod(i); // 取余
    72. if( i == 0 ) // 处理特殊情况(首结点)
    73. {
    74. Node* toDel = this->m_header.next; // 获取首结点地址
    75. if( toDel != NULL )
    76. {
    77. this->m_header.next = toDel->next; // 头结点指向 1 结点
    78. this->m_length--; // 当前线性表长度 -1
    79. if( this->m_length > 0 ) // 当前结点不是最后一个结点
    80. {
    81. last_to_first(); // 将链表首尾相连
    82. if( this->m_current == toDel ) // 判断游标是否指向 待删除结点的地址
    83. {
    84. this->m_current = toDel->next; // 指向 待删除结点的下一个结点的地址
    85. }
    86. }
    87. else
    88. {
    89. this->m_header.next = NULL; // 头结点置 NULL
    90. this->m_current = NULL; // 当前结点置 NULL
    91. }
    92. this->destroy(toDel); // 为了异常安全,最后销毁结点
    93. }
    94. else
    95. {
    96. ret = false;
    97. }
    98. }
    99. else
    100. {
    101. ret = LinkList<T>::remove(i); // 若不是特殊情况,调用父类函数实现
    102. }
    103. return ret;
    104. }
    105. /**********************************************************************
    106. * Function: set()
    107. * Description: 修改第i个结点的值
    108. * Input: i 待修改结点的位置
    109. * Output:
    110. * Return: bool 判断修改结点位置是否合法
    111. * Others: O(n)
    112. * Modify Date Version Author Modification
    113. * ------------------------------------------------------------
    114. * 2022/03/19 1.0 Create
    115. **********************************************************************/
    116. bool set(int i, const T& e)
    117. {
    118. return LinkList<T>::set(mod(i), e);
    119. }
    120. /**********************************************************************
    121. * Function: get()
    122. * Description: 获取第i个结点的值(函数重载)
    123. * Input: i 待获取结点的位置
    124. * Output:
    125. * Return: bool 判断获取结点位置是否合法
    126. * Others: O(n)
    127. * Modify Date Version Author Modification
    128. * ------------------------------------------------------------
    129. * 2022/03/19 1.0 Create
    130. **********************************************************************/
    131. T get(int i) const
    132. {
    133. return LinkList<T>::get(mod(i));
    134. }
    135. bool get(int i, T& e) const
    136. {
    137. return LinkList<T>::get(mod(i), e);
    138. }
    139. /**********************************************************************
    140. * Function: find()
    141. * Description: 查找指定元素的位置
    142. * Input: e 待查找结点的值(value)
    143. * Output:
    144. * Return: int 返回结点的位置
    145. * Others: O(n)
    146. * Modify Date Version Author Modification
    147. * ------------------------------------------------------------
    148. * 2022/03/19 1.0 Create
    149. **********************************************************************/
    150. int find(const T& e) const
    151. {
    152. int ret = -1;
    153. Node* slider = this->m_header.next; // 获取 0 元素的地址
    154. for(int i=0; i<this->m_length; i++)
    155. {
    156. if( slider->value == e ) // 判断值是否相等
    157. {
    158. ret = i; // 获取位置
    159. break;
    160. }
    161. slider = slider->next; // 移动到下一个结点
    162. }
    163. return ret;
    164. }
    165. /**********************************************************************
    166. * Function: clear()
    167. * Description: 清空线性表
    168. * Input:
    169. * Output:
    170. * Return:
    171. * Others: O(n)
    172. * Modify Date Version Author Modification
    173. * ------------------------------------------------------------
    174. * 2022/03/19 1.0 Create
    175. **********************************************************************/
    176. void clear()
    177. {
    178. while( this->m_length > 1 )
    179. {
    180. remove(1); // 为了效率 remove(0)
    181. }
    182. if( this->m_length == 1 ) // 处理特殊情况(只剩首结点)
    183. {
    184. Node* toDel = this->m_header.next;
    185. this->m_header.next = NULL;
    186. this->m_length = 0;
    187. this->m_current = NULL;
    188. this->destroy(toDel);
    189. }
    190. }
    191. /**********************************************************************
    192. * Function: move()
    193. * Description: 将游标定位到目标位置(i)
    194. * Input: i 移动到第i个元素
    195. * step 步进默认为 1
    196. * Output:
    197. * Return: bool 判断i位置是否合法
    198. * Others: O(n)
    199. * Modify Date Version Author Modification
    200. * ------------------------------------------------------------
    201. * 2022/03/19 1.0 Create
    202. **********************************************************************/
    203. bool move(int i, int step) // 遍历所有元素
    204. {
    205. return LinkList<T>::move(mod(i), step);
    206. }
    207. /**********************************************************************
    208. * Function: end()
    209. * Description: 游标是否到达尾部
    210. * Input:
    211. * Output:
    212. * Return: bool 游标是否到达尾部
    213. * Others:
    214. * Modify Date Version Author Modification
    215. * ------------------------------------------------------------
    216. * 2022/03/19 1.0 Create
    217. **********************************************************************/
    218. bool end()
    219. {
    220. return (this->m_length == 0) || (this->m_current == NULL);
    221. }
    222. /**********************************************************************
    223. * Function: ~LinkList()
    224. * Description: 析构函数 - 清空线性表
    225. * Input:
    226. * Output:
    227. * Return:
    228. * Others: O(n)
    229. * Modify Date Version Author Modification
    230. * ------------------------------------------------------------
    231. * 2022/03/19 1.0 Create
    232. **********************************************************************/
    233. ~CircleList()
    234. {
    235. clear();
    236. }
    237. };
    238. }
    239. #endif // CIRCLELIST_H_

    7、循环链表的应用

    • 约瑟夫环问题

            

    8、编程实验:约瑟夫问题

    main.cpp

    1. #include <iostream>
    2. #include "./DTLib/CircleList.h"
    3. using namespace std;
    4. using namespace DTLib;
    5. void josephus(int n, int s, int m)
    6. {
    7. CircleList<int> cl;
    8. for(int i=1; i<=n; i++)
    9. {
    10. cl.insert(i);
    11. }
    12. cl.move(s-1,m-1); //游标指向0处,步长2
    13. int i=0;
    14. while( cl.length() > 0 )
    15. {
    16. cl.next();
    17. cout << cl.current() <<endl; //当前要自杀的
    18. int index=cl.find(cl.current());
    19. cl.remove(index);
    20. }
    21. }
    22. int main()
    23. {
    24. josephus(41,1,3); //41个人,从1号开始数,数到第三个人开始自杀
    25. return 0;
    26. }

    9、小结

    • 循环链表是一种特殊的单链表
    • 尾结点的指针域保存了首结点的地址
    • 特殊处理首元素的插入操作和删除操作
    • 重新实现清空操作遍历操作

     

    三十、双向链表的实现

    1、交流中

            

    2、单链表的另一个缺陷

    • 单向性
      • 只能从头结点开始高效访问链表中的数据元素
    • 缺陷
      • 如果需要逆向访问单链表中的数据元素将极其低效

            

    3、新的线性表

    • 设计思路:

    在“单链表”的结点中增加一个指针 pre ,用于指向当前结点的前驱结点。

            

    4、双向链表的继承层次结构

    5、DualLinkList的定义

    6、编程实验:双向链表的实现

    DualLinkList.h

    1. #ifndef DUALLINKLIST_H_
    2. #define DUALLINKLIST_H_
    3. /*******************************************************************************
    4. * Include Files *
    5. *******************************************************************************/
    6. #include "List.h"
    7. #include "Exception.h"
    8. /*******************************************************************************
    9. * Type Definition *
    10. *******************************************************************************/
    11. namespace DTLib
    12. {
    13. template < typename T >
    14. class DualLinkList : public List<T>
    15. {
    16. protected:
    17. struct Node : public Object
    18. {
    19. T value; // 数据域
    20. Node* next; // 后继指针
    21. Node* pre; // 前驱指针
    22. };
    23. mutable struct : public Object // mutable 突破const的限制而设置,永远处于可变的状态,即使在一个const函数中
    24. {
    25. char reserved[sizeof(T)]; // 为了与Node内存对齐,以便后续使用强制类型转换,继承于Object同理。
    26. Node* next; // 指向首结点
    27. Node* pre; // 内存对齐
    28. } m_header; // 创建头结点 不直接用 Node m_header,因为T有可能是类,在类运行构造函数时,可能会抛出异常
    29. int m_length; // 当前线性表的长度
    30. int m_step; // 步进次数 遍历元素的时候使用 move(); end(); next(); current()
    31. Node* m_current; // 游标 遍历元素的时候使用 move(); end(); next(); current()
    32. /**********************************************************************
    33. * Function: position()
    34. * Description: 移动i次,返回第i-1个结点的地址
    35. * Input: i 数组类地址
    36. * m_header 头结点地址
    37. * Output:
    38. * Return: Node 返回第i-1个结点的地址
    39. * Others: O(n)
    40. * Modify Date Version Author Modification
    41. * ------------------------------------------------------------
    42. * 2022/03/19 1.0 Create
    43. **********************************************************************/
    44. Node* position(int i) const
    45. {
    46. Node* ret = reinterpret_cast<Node*>(&m_header); // 头结点地址 - 强制类型转换
    47. for(int p=0; p<i; p++) // 移动i次
    48. {
    49. ret = ret->next;
    50. }
    51. return ret;
    52. }
    53. /**********************************************************************
    54. * Function: create()
    55. * Description: 创建新结点(堆空间)
    56. * Input:
    57. * Output:
    58. * Return: Node 返回新结点的地址
    59. * Others:
    60. * Modify Date Version Author Modification
    61. * ------------------------------------------------------------
    62. * 2022/03/19 1.0 Create
    63. **********************************************************************/
    64. virtual Node* create()
    65. {
    66. return new Node();
    67. }
    68. /**********************************************************************
    69. * Function: destroy()
    70. * Description: 销毁结点(堆空间)
    71. * Input: pn 待销毁的结点
    72. * Output:
    73. * Return:
    74. * Others:
    75. * Modify Date Version Author Modification
    76. * ------------------------------------------------------------
    77. * 2022/03/19 1.0 Create
    78. **********************************************************************/
    79. virtual void destroy(Node* pn)
    80. {
    81. delete pn;
    82. }
    83. public:
    84. /**********************************************************************
    85. * Function: DualLinkList()
    86. * Description: 构造函数 - 初始化参数
    87. * Input:
    88. * Output:
    89. * Return:
    90. * Others:
    91. * Modify Date Version Author Modification
    92. * ------------------------------------------------------------
    93. * 2022/03/19 1.0 Create
    94. **********************************************************************/
    95. DualLinkList()
    96. {
    97. m_header.next = NULL;
    98. m_header.pre = NULL;
    99. m_length = 0;
    100. m_step = 1;
    101. m_current = NULL;
    102. }
    103. /**********************************************************************
    104. * Function: insert()
    105. * Description: 插入新结点(函数重载)
    106. * Input: i 在位置i插入新结点(默认插在最后)
    107. * e 带插入结点的数据(value)
    108. * Output:
    109. * Return: bool 判断插入结点位置是否合法
    110. * Others: 异常 申请内存是否成功
    111. * Modify Date Version Author Modification
    112. * ------------------------------------------------------------
    113. * 2022/03/19 1.0 Create
    114. **********************************************************************/
    115. bool insert(const T& e)
    116. {
    117. return insert(m_length, e); // 新结点插在最后
    118. }
    119. bool insert(int i, const T& e)
    120. {
    121. bool ret = ((0 <= i) && (i <= m_length)); // 位置i合法性校验
    122. if( ret )
    123. {
    124. Node* node = create(); // 创建新结点 - 申请内存
    125. if( node != NULL )
    126. {
    127. Node* current = position(i); // 获取新结点前一个结点的地址
    128. Node* next = current->next; // 获取新结点后一个结点的地址
    129. node->value = e; // 新结点的数据域(value)赋值
    130. node->next = next; // 新结点后继指针赋值
    131. current->next = node; // 前一个结点后继指向新结点
    132. if( current != reinterpret_cast<Node*>(&m_header) ) // 前一个结点不为头结点
    133. {
    134. node->pre = current; // 新结点前继指针赋值
    135. }
    136. else
    137. {
    138. node->pre = NULL; // 新结点前继指针置 0
    139. }
    140. if( next != NULL ) // 后一个结点存在
    141. {
    142. next->pre = node; // 后一个结点的前继指针赋值
    143. }
    144. m_length++; // 当前线性表的长度 +1
    145. }
    146. else
    147. {
    148. THROW_EXCEPTION(NoEnoughMemoryException, "No memory to insert new element ...");
    149. }
    150. }
    151. return ret;
    152. }
    153. /**********************************************************************
    154. * Function: remove()
    155. * Description: 删除结点
    156. * Input: i 在位置i删除结点
    157. * Output:
    158. * Return: bool 判断删除结点位置是否合法
    159. * Others: O(n)
    160. * Modify Date Version Author Modification
    161. * ------------------------------------------------------------
    162. * 2022/03/19 1.0 Create
    163. **********************************************************************/
    164. bool remove(int i)
    165. {
    166. bool ret = ((0 <= i) && (i < m_length)); // 位置i合法性校验
    167. if( ret )
    168. {
    169. Node* current = position(i); // 获取待删除结点前一个结点的地址
    170. Node* toDel = current->next; // 临时保存 待删除结点的地址
    171. Node* next = toDel->next; // 获取待删除结点后一个结点的地址
    172. if( m_current == toDel ) // 判断游标是否指向 待删除结点的地址
    173. {
    174. m_current = next; // 指向 待删除结点的下一个结点的地址
    175. }
    176. current->next = next; // 待删除结点的下一个结点的地址,赋值给待删除结点的前一个结点的next
    177. if( next != NULL ) // 待删除结点后还有结点
    178. {
    179. next->pre = toDel->pre; // 待删除结点的前驱地址,赋值给下一个结点的前驱指针
    180. }
    181. m_length--; // 当前线性表的长度 -1 为了防止元素为类时,析构函数抛出异常,无法保证链表的安全性
    182. destroy(toDel); // 释放该结点所占得内存
    183. }
    184. return ret;
    185. }
    186. /**********************************************************************
    187. * Function: set()
    188. * Description: 修改第i个结点的值
    189. * Input: i 待修改结点的位置
    190. * Output:
    191. * Return: bool 判断修改结点位置是否合法
    192. * Others: O(n)
    193. * Modify Date Version Author Modification
    194. * ------------------------------------------------------------
    195. * 2022/03/19 1.0 Create
    196. **********************************************************************/
    197. bool set(int i, const T& e)
    198. {
    199. bool ret = ((0 <= i) && (i < m_length)); // 位置i合法性校验
    200. if( ret )
    201. {
    202. position(i)->next->value = e; // 待修改结点的前一个结点->next == 待修改的结点的地址
    203. }
    204. return ret;
    205. }
    206. /**********************************************************************
    207. * Function: get()
    208. * Description: 获取第i个结点的值(函数重载)
    209. * Input: i 待获取结点的位置
    210. * Output:
    211. * Return: bool 判断获取结点位置是否合法
    212. * Others: O(n)
    213. * Modify Date Version Author Modification
    214. * ------------------------------------------------------------
    215. * 2022/03/19 1.0 Create
    216. **********************************************************************/
    217. virtual T get(int i) const
    218. {
    219. T ret;
    220. if( get(i, ret) )
    221. {
    222. return ret;
    223. }
    224. else
    225. {
    226. THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ...");
    227. }
    228. return ret;
    229. }
    230. bool get(int i, T& e) const
    231. {
    232. bool ret = ((0 <= i) && (i < m_length)); // 位置i合法性校验
    233. if( ret )
    234. {
    235. e = position(i)->next->value; // 待获取结点的前一个结点->next == 待获取的结点的地址
    236. }
    237. return ret;
    238. }
    239. /**********************************************************************
    240. * Function: find()
    241. * Description: 查找指定元素的位置
    242. * Input: e 待查找结点的值(value)
    243. * Output:
    244. * Return: int 返回结点的位置
    245. * Others: O(n)
    246. * Modify Date Version Author Modification
    247. * ------------------------------------------------------------
    248. * 2022/03/19 1.0 Create
    249. **********************************************************************/
    250. int find(const T& e) const
    251. {
    252. int ret = -1;
    253. int i = 0;
    254. Node* node = m_header.next; // 获取 0 元素的地址
    255. while( node )
    256. {
    257. if( node->value == e ) // 判断值是否相等
    258. {
    259. ret = i; // 获取位置
    260. break;
    261. }
    262. else
    263. {
    264. node = node->next; // 移动到下一个结点
    265. i++; // 位置 +1
    266. }
    267. }
    268. return ret;
    269. }
    270. /**********************************************************************
    271. * Function: length()
    272. * Description: 当前线性表的长度
    273. * Input:
    274. * Output:
    275. * Return: int 当前线性表的长度
    276. * Others: O(1)
    277. * Modify Date Version Author Modification
    278. * ------------------------------------------------------------
    279. * 2022/03/19 1.0 Create
    280. **********************************************************************/
    281. int length() const
    282. {
    283. return m_length;
    284. }
    285. /**********************************************************************
    286. * Function: clear()
    287. * Description: 清空线性表
    288. * Input:
    289. * Output:
    290. * Return:
    291. * Others: O(n)
    292. * Modify Date Version Author Modification
    293. * ------------------------------------------------------------
    294. * 2022/03/19 1.0 Create
    295. **********************************************************************/
    296. void clear()
    297. {
    298. while( m_length > 0 ) // 循环删除首结点
    299. {
    300. remove(0);
    301. }
    302. }
    303. /*
    304. 遍历所有元素 推荐使用方法
    305. 移动到0号元素 判断是否到尾部 移动到下一个结点
    306. for (list.move(0); !list.end();list.next())
    307. {
    308. cout << list.current() << endl;
    309. }
    310. 移动到尾元素 判断是否到首部 移动到上一个结点
    311. for (list.move(list.length()-1); !list.end();list.pre())
    312. {
    313. cout << list.current() << endl;
    314. }
    315. */
    316. /**********************************************************************
    317. * Function: move()
    318. * Description: 将游标定位到目标位置(i)
    319. * Input: i 移动到第i个元素
    320. * step 步进默认为 1
    321. * Output:
    322. * Return: bool 判断i位置是否合法
    323. * Others:
    324. * Modify Date Version Author Modification
    325. * ------------------------------------------------------------
    326. * 2022/03/19 1.0 Create
    327. **********************************************************************/
    328. virtual bool move(int i, int step = 1)
    329. {
    330. bool ret = (0 <= i) && (i < m_length) && (step > 0);
    331. if( ret )
    332. {
    333. m_current = position(i)->next; // 目标位置的地址
    334. m_step = step;
    335. }
    336. return ret;
    337. }
    338. /**********************************************************************
    339. * Function: end()
    340. * Description: 游标是否到达尾部
    341. * Input:
    342. * Output:
    343. * Return: bool 游标是否到达尾部
    344. * Others:
    345. * Modify Date Version Author Modification
    346. * ------------------------------------------------------------
    347. * 2022/03/19 1.0 Create
    348. **********************************************************************/
    349. virtual bool end()
    350. {
    351. return (m_current == NULL);
    352. }
    353. /**********************************************************************
    354. * Function: current()
    355. * Description: 获取游标所指向的数据元素
    356. * Input:
    357. * Output:
    358. * Return: T 游标所指向的数据元素
    359. * Others: 异常 游标已到尾部,无法获取到值
    360. * Modify Date Version Author Modification
    361. * ------------------------------------------------------------
    362. * 2022/03/19 1.0 Create
    363. **********************************************************************/
    364. virtual T current()
    365. {
    366. if( !end() ) // 游标是否到达尾部
    367. {
    368. return m_current->value;
    369. }
    370. else
    371. {
    372. THROW_EXCEPTION(InvalidOperationException, "No value at current position ...");
    373. }
    374. }
    375. /**********************************************************************
    376. * Function: next()
    377. * Description: 向后移动游标 m_step次
    378. * Input:
    379. * Output:
    380. * Return: bool 是否成功移动游标 m_step次
    381. * Others:
    382. * Modify Date Version Author Modification
    383. * ------------------------------------------------------------
    384. * 2022/03/19 1.0 Create
    385. **********************************************************************/
    386. virtual bool next()
    387. {
    388. int i = 0;
    389. while( (i < m_step) && !end() ) // 移动次数是否为m_step && 游标是否到达尾部
    390. {
    391. m_current = m_current->next; // 移动一次游标
    392. i++;
    393. }
    394. return (i == m_step);
    395. }
    396. /**********************************************************************
    397. * Function: pre()
    398. * Description: 向前移动游标 m_step次
    399. * Input:
    400. * Output:
    401. * Return: bool 是否成功移动游标 m_step次
    402. * Others:
    403. * Modify Date Version Author Modification
    404. * ------------------------------------------------------------
    405. * 2022/03/19 1.0 Create
    406. **********************************************************************/
    407. virtual bool pre()
    408. {
    409. int i = 0;
    410. while( (i < m_step) && !end() ) // 移动次数是否为m_step && 游标是否到达尾部
    411. {
    412. m_current = m_current->pre; // 移动一次游标
    413. i++;
    414. }
    415. return (i == m_step);
    416. }
    417. /**********************************************************************
    418. * Function: ~DualLinkList()
    419. * Description: 析构函数 - 清空线性表
    420. * Input:
    421. * Output:
    422. * Return:
    423. * Others: O(n)
    424. * Modify Date Version Author Modification
    425. * ------------------------------------------------------------
    426. * 2022/03/19 1.0 Create
    427. **********************************************************************/
    428. ~DualLinkList()
    429. {
    430. clear();
    431. }
    432. };
    433. }
    434. #endif // DUALLINKLIST_H_

    7、小结

    • 双向链表是为了弥补单链表的缺陷而重新设计的
    • 在概念上,双向链表不是单链表,没有继承关系
    • 双向链表中的游标能够直接访问当前结点的前驱和后继
    • 双向链表是线性表概念的最终实现(更贴近理论上的线性表)

    8、深度思考

    • 有些设计,会让两者的呈现继承关系。没有对与错。考虑的不同。
    • 代码后期的维护性和软件产品的维护性。

    三十一、老生常谈的两个宏(Linux)

    1、Linux内核中常用的两个宏定义

    2、见招拆招 - 第一式:编译器做了什么?

    • offsetof用于计算TYPE结构体中MEMBER成员的偏移位置。

    • 编译器清楚的知道结构体成员变量的偏移位置
    • 通过结构体变量首地址偏移量定位成员变量

    3、编程实验:offsetof 原理剖析

    1. #include <stdio.h>
    2. #ifndef offsetof
    3. #define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER)
    4. #endif
    5. struct ST
    6. {
    7. int i; // 0
    8. int j; // 4
    9. char c; // 8
    10. };
    11. void func(struct ST* pst)
    12. {
    13. int* pi = &(pst->i); // 0
    14. int* pj = &(pst->j); // 4
    15. char* pc = &(pst->c); // 8
    16. printf("pst = %p\n", pst);
    17. printf("pi = %p\n", pi);
    18. printf("pj = %p\n", pj);
    19. printf("pc = %p\n", pc);
    20. }
    21. int main()
    22. {
    23. struct ST s = {0};
    24. func(&s);
    25. func(NULL);
    26. printf("offset i: %ld\n", offsetof(struct ST, i));
    27. printf("offset j: %ld\n", offsetof(struct ST, j));
    28. printf("offset c: %ld\n", offsetof(struct ST, c));
    29. return 0;
    30. }

    4、见招拆招 - 第二式:({})是何方神圣?

    • ({}) 是GNU C编译器的语法扩展
    • ({}) 与逗号表达式类似,结果为最后一个语句的值

    5、见招拆招 - 第三式:typeof是一个关键字吗?

    • typeof是GNU C编译器的特有关键字
    • typeof只在编译期生效,用于得到变量的类型

            

    6、见招拆招 - 第四式:最后的原理

    当已知pc和结构成员地址偏移量,求首地址。

    7、编程实验:container_of 原理剖析

    1. #include <stdio.h>
    2. #ifndef offsetof
    3. #define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER)
    4. #endif
    5. #ifndef container_of
    6. #define container_of(ptr, type, member) ({ \
    7. const typeof(((type*)0)->member)* __mptr = (ptr); \
    8. (type*)((char*)__mptr - offsetof(type, member)); })
    9. #endif
    10. #ifndef container_of_new
    11. #define container_of_new(ptr, type, member) ((type*)((char*)(ptr) - offsetof(type, member)))
    12. #endif
    13. struct ST
    14. {
    15. int i; // 0
    16. int j; // 4
    17. char c; // 8
    18. };
    19. void method_1()
    20. {
    21. int a = 0;
    22. int b = 0;
    23. int r = (
    24. a = 1,
    25. b = 2,
    26. a + b
    27. );
    28. printf("r = %d\n", r);
    29. }
    30. void method_2()
    31. {
    32. int r = ( {
    33. int a = 1;
    34. int b = 2;
    35. a + b;
    36. } );
    37. printf("r = %d\n", r);
    38. }
    39. void type_of()
    40. {
    41. int i = 100;
    42. typeof(i) j = i;
    43. const typeof(j)* p = &j;
    44. printf("sizeof(j) = %d\n", sizeof(j));
    45. printf("j = %d\n", j);
    46. printf("*p = %d\n", *p);
    47. }
    48. int main()
    49. {
    50. // method_1();
    51. // method_2();
    52. // type_of();
    53. struct ST s = {0};
    54. char* pc = &s.c;
    55. int e = 0;
    56. int* pe = &e;
    57. struct ST* pst = container_of(pc, struct ST, c);
    58. printf("&s = %p\n", &s);
    59. printf("pst = %p\n", pst);
    60. return 0;
    61. }

    8、小结

    • 编译器清楚的知道结构体成员变量的偏移位置
    • ({ })与逗号表达式类似(但是可以定义新的局部变量),结果为最后一个语句的值
    • typeof只在编译期生效,用于得到变量的类型
    • container_of使用({})进行类型安全检查(逗号表达式中不可以定义变量)

     

    三十二、Linux内核链表剖析

    1、目标

    • 移植Linux内核链表,使其适用于非GNU编译器
    • 分析Linux内核中链表的基本实现

    2、Linux内核链表的位置及依赖

    • 位置
      • {linux-2.6.39}\\include\linux\list.h
    • 依赖
      • #include <linux/types.h>
      • #include <linux /stddef.h>
      • #include <linux/poison.h>
      • #include <linux/prefetch.h>

    3、移植时的注意事项

    • 清除文件间的依赖
      • 剥离依赖文件中与链表实现相关的代码
    • 清除平台相关代码(GNU C )
      • ({})
      •  typeof
      • _builtin_prefetch  (提高访问效率)  -  直接删除
      • static inline(支持同时使用)删除inline

    4、编程实验:Linux内核源码的移植

    list.h

    5、Linux内核链表的实现

    • 带头节点的双向循环链表,且头节点为表中成员
    • 头结点的next指针指向首结点
    • 头节点的prev指针指向尾结点

    6、Linux内核链表的结点定义

    7、使用struct list_head自定义链表结点

    8、编程实验:Linux内核链表初体验

    main.c

    9、Linux内核链表的插入操作

    • 在链表头部插入:list_add (new, head)
    • 在链表尾部插入:list_add_tail (new, head)

            

    10、Linux内核链表的删除操作

            

    11、Linux内核链表的遍历

    • 正向遍历:list_for_each(pos, head)
    • 逆向遍历:list_for_each_prev(pos, head)

    12、编程实验:Linux内核链表的使用

    main.c

    1. #include <stdio.h>
    2. #include "LinuxList.h"
    3. void list_demo_1()
    4. {
    5. struct Node
    6. {
    7. struct list_head head;
    8. int value;
    9. };
    10. struct Node l = {0};
    11. struct list_head* list = (struct list_head*)&l;
    12. struct list_head* slider = NULL;
    13. int i = 0;
    14. INIT_LIST_HEAD(list);
    15. printf("Insert begin ...\n");
    16. for(i=0; i<5; i++)
    17. {
    18. struct Node* n = (struct Node*)malloc(sizeof(struct Node));
    19. n->value = i;
    20. list_add_tail((struct list_head*)n, list);
    21. }
    22. list_for_each(slider, list)
    23. {
    24. printf("%d\n", ((struct Node*)slider)->value);
    25. }
    26. printf("Insert end ...\n");
    27. printf("Delete begin ...\n");
    28. list_for_each(slider, list)
    29. {
    30. if( ((struct Node*)slider)->value == 3 )
    31. {
    32. list_del(slider);
    33. free(slider);
    34. break;
    35. }
    36. }
    37. list_for_each(slider, list)
    38. {
    39. printf("%d\n", ((struct Node*)slider)->value);
    40. }
    41. printf("Delete end ...\n");
    42. }
    43. void list_demo_2()
    44. {
    45. struct Node
    46. {
    47. int value;
    48. struct list_head head;
    49. };
    50. struct Node l = {0};
    51. struct list_head* list = &l.head;
    52. struct list_head* slider = NULL;
    53. int i = 0;
    54. INIT_LIST_HEAD(list);
    55. printf("Insert begin ...\n");
    56. for(i=0; i<5; i++)
    57. {
    58. struct Node* n = (struct Node*)malloc(sizeof(struct Node));
    59. n->value = i;
    60. list_add(&n->head, list);
    61. }
    62. list_for_each(slider, list)
    63. {
    64. printf("%d\n", list_entry(slider, struct Node, head)->value);
    65. }
    66. printf("Insert end ...\n");
    67. printf("Delete begin ...\n");
    68. list_for_each(slider, list)
    69. {
    70. struct Node* n = list_entry(slider, struct Node, head);
    71. if( n->value == 3 )
    72. {
    73. list_del(slider);
    74. free(n);
    75. break;
    76. }
    77. }
    78. list_for_each(slider, list)
    79. {
    80. printf("%d\n", list_entry(slider, struct Node, head)->value);
    81. }
    82. printf("Delete end ...\n");
    83. }
    84. int main()
    85. {
    86. // list_demo_1();
    87. // list_demo_2();
    88. return 0;
    89. }

    13、小结

    • Linux内核链表移植时需要剔除依赖以及平台相关代码
    • Linux内核链表是带头节点的双向循环链表
    • 使用Linux内核链表时需要自定义链表结点
      • struct list_head 作为结点结构体的第一个成员或最后一个成员
      • struct list_head 作为最后一个成员时,需要使用list_entry
      • list_entry的定义中使用了container_of宏

     

    三十三、双向循环链表的实现

    1、目标

    • 使用Linux内核链表实现 DTLib中的双向循环链表
    • template < typename T > class DualCircleList;

    2、DTLib中双向循环链表的设计思路

    数据结点之间在逻辑上构成双向循环链表,头结点仅用于结点的定位。

    3、实现思路

    • 通过模板定义 DualCircleList类,继承自DualLinkList
    • 在DualCircleList内部使用Linux内核链表进行实现
    • 使用struct list_head定义 DualCircleList的头结点
    • 特殊处理:循环遍历时忽略头结点

    4、实现要点

    • 通过list_head进行目标结点定位( position(i) )
    • 通过list_entry将list_head指针转换为目标结点指针
    • 通过list_for_each 实现int find(const T&e)函数
    • 遍历函数中的next()pre()需要考虑跳过头结点

    5、编程实验:基于Linux内核链表的双向循环链表

    DualCircleList.h

    1. #ifndef DUALCIRCLELIST_H
    2. #define DUALCIRCLELIST_H
    3. #include "LinuxList.h"
    4. #include "DualLinkList.h"
    5. namespace DTLib
    6. {
    7. template < typename T >
    8. class DualCircleList : public DualLinkList<T>
    9. {
    10. protected:
    11. struct Node : public Object // 结点类型
    12. {
    13. list_head head; // Linux内核链表结点的结构体成员
    14. T value; // 数据域
    15. };
    16. list_head m_header; // 头结点
    17. list_head* m_current; // 游标 - 用于遍历
    18. /**********************************************************************
    19. * Function: position()
    20. * Description: 移动i次,返回第i-1个结点的地址
    21. * Input: i 数组类地址
    22. * m_header 头结点地址
    23. * Output:
    24. * Return: Node 返回第i-1个结点的地址
    25. * Others: O(n)
    26. * Modify Date Version Author Modification
    27. * ------------------------------------------------------------
    28. * 2022/03/18 1.0 Create
    29. **********************************************************************/
    30. list_head* position(int i) const
    31. {
    32. list_head* ret = const_cast<list_head*>(&m_header); // 头结点地址 - 强制类型转换
    33. for(int p=0; p<i; p++) // 移动i次游标
    34. {
    35. ret = ret->next;
    36. }
    37. return ret;
    38. }
    39. /**********************************************************************
    40. * Function: mod()
    41. * Description: 取余
    42. * Input: i 数组类地址
    43. * m_header 头结点地址
    44. * Output:
    45. * Return: Node 返回第i-1个结点的地址
    46. * Others: O(n)
    47. * Modify Date Version Author Modification
    48. * ------------------------------------------------------------
    49. * 2022/03/18 1.0 Create
    50. **********************************************************************/
    51. int mod(int i) const
    52. {
    53. return (this->m_length == 0) ? 0 : (i % this->m_length);
    54. }
    55. public:
    56. /**********************************************************************
    57. * Function: DualCircleList()
    58. * Description: 构造函数 - 初始化参数
    59. * Input:
    60. * Output:
    61. * Return:
    62. * Others:
    63. * Modify Date Version Author Modification
    64. * ------------------------------------------------------------
    65. * 2022/04/12 1.0 Create
    66. **********************************************************************/
    67. DualCircleList()
    68. {
    69. this->m_length = 0;
    70. this->m_step = 1;
    71. m_current = NULL;
    72. INIT_LIST_HEAD(&m_header); // Linux链表头结点初始化
    73. }
    74. /**********************************************************************
    75. * Function: insert()
    76. * Description: 插入新结点(函数重载)
    77. * Input: i 在位置i插入新结点(默认插在最后)
    78. * e 带插入结点的数据(value)
    79. * Output:
    80. * Return: bool 判断插入结点位置是否合法
    81. * Others: 异常 申请内存是否成功
    82. * Modify Date Version Author Modification
    83. * ------------------------------------------------------------
    84. * 2022/03/18 1.0 Create
    85. **********************************************************************/
    86. bool insert(const T& e)
    87. {
    88. return insert(this->m_length, e);
    89. }
    90. bool insert(int i, const T& e)
    91. {
    92. bool ret = true;
    93. Node* node = new Node();
    94. i = i % (this->m_length + 1); // 取余
    95. if( node != NULL )
    96. {
    97. node->value = e;
    98. list_add_tail(&node->head, position(i)->next);
    99. this->m_length++;
    100. }
    101. else
    102. {
    103. THROW_EXCEPTION(NoEnoughMemoryException, "No memory to insert new element ...");
    104. }
    105. return ret;
    106. }
    107. /**********************************************************************
    108. * Function: remove()
    109. * Description: 删除结点
    110. * Input: i 在位置i删除结点
    111. * Output:
    112. * Return: bool 判断删除结点位置是否合法
    113. * Others: O(n)
    114. * Modify Date Version Author Modification
    115. * ------------------------------------------------------------
    116. * 2022/03/18 1.0 Create
    117. **********************************************************************/
    118. bool remove(int i)
    119. {
    120. bool ret = true;
    121. i = mod(i);
    122. ret = ((0 <= i) && (i < this->m_length));
    123. if( ret )
    124. {
    125. list_head* toDel = position(i)->next;
    126. if( m_current == toDel )
    127. {
    128. m_current = toDel->next;
    129. }
    130. list_del(toDel);
    131. this->m_length--;
    132. delete list_entry(toDel, Node, head);
    133. }
    134. return ret;
    135. }
    136. /**********************************************************************
    137. * Function: set()
    138. * Description: 修改第i个结点的值
    139. * Input: i 待修改结点的位置
    140. * Output:
    141. * Return: bool 判断修改结点位置是否合法
    142. * Others: O(n)
    143. * Modify Date Version Author Modification
    144. * ------------------------------------------------------------
    145. * 2022/03/18 1.0 Create
    146. **********************************************************************/
    147. bool set(int i, const T& e)
    148. {
    149. bool ret = true;
    150. i = mod(i);
    151. ret = ((0 <= i) && (i < this->m_length));
    152. if( ret )
    153. {
    154. list_entry(position(i)->next, Node, head)->value = e;
    155. }
    156. return ret;
    157. }
    158. /**********************************************************************
    159. * Function: get()
    160. * Description: 获取第i个结点的值(函数重载)
    161. * Input: i 待获取结点的位置
    162. * Output:
    163. * Return: bool 判断获取结点位置是否合法
    164. * Others: O(n)
    165. * Modify Date Version Author Modification
    166. * ------------------------------------------------------------
    167. * 2022/03/18 1.0 Create
    168. **********************************************************************/
    169. T get(int i) const
    170. {
    171. T ret;
    172. if( get(i, ret) )
    173. {
    174. return ret;
    175. }
    176. else
    177. {
    178. THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ...");
    179. }
    180. return ret;
    181. }
    182. bool get(int i, T& e) const
    183. {
    184. bool ret = true;
    185. i = mod(i);
    186. ret = ((0 <= i) && (i < this->m_length));
    187. if( ret )
    188. {
    189. e = list_entry(position(i)->next, Node, head)->value;
    190. }
    191. return ret;
    192. }
    193. /**********************************************************************
    194. * Function: find()
    195. * Description: 查找指定元素的位置
    196. * Input: e 待查找结点的值(value)
    197. * Output:
    198. * Return: int 返回结点的位置
    199. * Others: O(n)
    200. * Modify Date Version Author Modification
    201. * ------------------------------------------------------------
    202. * 2022/03/18 1.0 Create
    203. **********************************************************************/
    204. int find(const T& e) const
    205. {
    206. int ret = -1;
    207. int i = 0;
    208. list_head* slider = NULL;
    209. list_for_each(slider, &m_header)
    210. {
    211. if( list_entry(slider, Node, head)->value == e )
    212. {
    213. ret = i;
    214. break;
    215. }
    216. i++;
    217. }
    218. return ret;
    219. }
    220. /**********************************************************************
    221. * Function: length()
    222. * Description: 当前线性表的长度
    223. * Input:
    224. * Output:
    225. * Return: int 当前线性表的长度
    226. * Others: O(1)
    227. * Modify Date Version Author Modification
    228. * ------------------------------------------------------------
    229. * 2022/03/18 1.0 Create
    230. **********************************************************************/
    231. int length() const
    232. {
    233. return this->m_length;
    234. }
    235. /**********************************************************************
    236. * Function: clear()
    237. * Description: 清空线性表
    238. * Input:
    239. * Output:
    240. * Return:
    241. * Others: O(n)
    242. * Modify Date Version Author Modification
    243. * ------------------------------------------------------------
    244. * 2022/03/18 1.0 Create
    245. **********************************************************************/
    246. void clear()
    247. {
    248. while( this->m_length > 0 )
    249. {
    250. remove(0);
    251. }
    252. }
    253. /*
    254. 遍历所有元素 推荐使用方法
    255. 移动到0号元素 判断是否到尾部 移动到下一个结点
    256. for (list.move(0); !list.end();list.next())
    257. {
    258. cout << list.current() << endl;
    259. }
    260. */
    261. /**********************************************************************
    262. * Function: move()
    263. * Description: 将游标定位到目标位置(i)
    264. * Input: i 移动到第i个元素
    265. * step 步进默认为 1
    266. * Output:
    267. * Return: bool 判断i位置是否合法
    268. * Others:
    269. * Modify Date Version Author Modification
    270. * ------------------------------------------------------------
    271. * 2022/03/18 1.0 Create
    272. **********************************************************************/
    273. bool move(int i, int step = 1)
    274. {
    275. bool ret = (step > 0);
    276. i = mod(i);
    277. ret = ret && ((0 <= i) && (i < this->m_length));
    278. if( ret )
    279. {
    280. m_current = position(i)->next;
    281. this->m_step = step;
    282. }
    283. return ret;
    284. }
    285. /**********************************************************************
    286. * Function: end()
    287. * Description: 游标是否到达尾部
    288. * Input:
    289. * Output:
    290. * Return: bool 游标是否到达尾部
    291. * Others:
    292. * Modify Date Version Author Modification
    293. * ------------------------------------------------------------
    294. * 2022/03/18 1.0 Create
    295. **********************************************************************/
    296. bool end()
    297. {
    298. return (m_current == NULL) || (this->m_length == 0);
    299. }
    300. /**********************************************************************
    301. * Function: current()
    302. * Description: 获取游标所指向的数据元素
    303. * Input:
    304. * Output:
    305. * Return: T 游标所指向的数据元素
    306. * Others: 异常 游标已到尾部,无法获取到值
    307. * Modify Date Version Author Modification
    308. * ------------------------------------------------------------
    309. * 2022/03/18 1.0 Create
    310. **********************************************************************/
    311. T current()
    312. {
    313. if( !end() )
    314. {
    315. return list_entry(m_current, Node, head)->value;
    316. }
    317. else
    318. {
    319. THROW_EXCEPTION(InvalidOperationException, "No value at current position ...");
    320. }
    321. }
    322. /**********************************************************************
    323. * Function: next()
    324. * Description: 移动游标 m_step次
    325. * Input:
    326. * Output:
    327. * Return: bool 是否成功移动游标 m_step次
    328. * Others:
    329. * Modify Date Version Author Modification
    330. * ------------------------------------------------------------
    331. * 2022/03/18 1.0 Create
    332. **********************************************************************/
    333. bool next()
    334. {
    335. int i = 0;
    336. while( (i < this->m_step) && !end() )
    337. {
    338. if( m_current != &m_header )
    339. {
    340. m_current = m_current->next;
    341. i++;
    342. }
    343. else
    344. {
    345. m_current = m_current->next;
    346. }
    347. }
    348. if( m_current == &m_header )
    349. {
    350. m_current = m_current->next;
    351. }
    352. return (i == this->m_step);
    353. }
    354. /**********************************************************************
    355. * Function: pre()
    356. * Description: 向前移动游标 m_step次
    357. * Input:
    358. * Output:
    359. * Return: bool 是否成功移动游标 m_step次
    360. * Others:
    361. * Modify Date Version Author Modification
    362. * ------------------------------------------------------------
    363. * 2022/03/19 1.0 Create
    364. **********************************************************************/
    365. bool pre()
    366. {
    367. int i = 0;
    368. while( (i < this->m_step) && !end() )
    369. {
    370. if( m_current != &m_header )
    371. {
    372. m_current = m_current->prev;
    373. i++;
    374. }
    375. else
    376. {
    377. m_current = m_current->prev;
    378. }
    379. }
    380. if( m_current == &m_header )
    381. {
    382. m_current = m_current->prev;
    383. }
    384. return (i == this->m_step);
    385. }
    386. /**********************************************************************
    387. * Function: ~DualLinkList()
    388. * Description: 析构函数 - 清空线性表
    389. * Input:
    390. * Output:
    391. * Return:
    392. * Others: O(n)
    393. * Modify Date Version Author Modification
    394. * ------------------------------------------------------------
    395. * 2022/03/19 1.0 Create
    396. **********************************************************************/
    397. ~DualCircleList()
    398. {
    399. clear();
    400. }
    401. };
    402. }
    403. #endif // DUALCIRCLELIST_H

    6、小结

    • Linux内核链表是带头结点的双向循环链表
    • DualCircleList使用Linux内核链表进行内部实现
    • DualCircleList在循环遍历时需要跳过头结点
    • list_head指针转换为目标结点指针时,使用list_entry

    7、思考题

    下面代码中的pn1和pn2是否相等?为什么?

  • 相关阅读:
    python相关岗位面试题总结(五)(持续更新)
    GBase XDM API遍历记录集
    [OtterCTF 2018] 电子取证
    Qt Designer基础控件介绍
    今天告诉你界面控件DevExpress WinForms为何弃用经典视觉样式
    CCF CSP认证 历年题目自练Day37
    【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
    一篇带你搞定⭐《生产环境JVM日志配置》⭐
    HashMap -- 调研
    2022杭电多校第七场题解
  • 原文地址:https://blog.csdn.net/qq_38426928/article/details/125464961