数据结构-双向链表&双向循环链表

女爷i 2021-10-01 00:40 696阅读 0赞

借图:http://www.cnblogs.com/skywang12345/p/3561803.html\#a33

双向链表

双向链表(双链表)是链表的一种。和单链表一样,双链表也是由节点组成,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。

922236-20171220110004678-643077430.png

922236-20171220110011240-853997173.png

实现:接口

ContractedBlock.gif ExpandedBlockStart.gif

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace _001_线性表
  7. {
  8. interface IListDS<T>
  9. {
  10. int GetLength();
  11. void Clear();
  12. bool IsEmpty();
  13. void Add(T item);
  14. void Insert(T item, int index);
  15. T Delete(int index);
  16. T this[int index] { get; }
  17. T GetEle(int index);
  18. int Locate(T value);
  19. }
  20. }

双向节点:

ContractedBlock.gif ExpandedBlockStart.gif

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace _001_线性表
  6. {
  7. /// <summary>
  8. /// 双向节点
  9. /// </summary>
  10. /// <typeparam name="T"></typeparam>
  11. class DbNode<T>
  12. {
  13. private T data;
  14. private DbNode<T> prev;
  15. private DbNode<T> next;
  16. public DbNode(T val,DbNode<T> p,DbNode<T> n)
  17. {
  18. this.data = val;
  19. this.prev = p;
  20. this.next = n;
  21. }
  22. public DbNode(DbNode<T> p)
  23. {
  24. next = p;
  25. }
  26. public DbNode(T val)
  27. {
  28. data = val;
  29. next = null;
  30. prev = null;
  31. }
  32. public DbNode()
  33. {
  34. data = default(T);
  35. next = null;
  36. prev = null;
  37. }
  38. public T Data
  39. {
  40. get { return data; }
  41. set { data = value; }
  42. }
  43. public DbNode<T> Prev
  44. {
  45. get { return prev; }
  46. set { prev = value; }
  47. }
  48. public DbNode<T> Next
  49. {
  50. get { return next; }
  51. set { next = value; }
  52. }
  53. public void SetNode(DbNode<T> pre,DbNode<T> next)
  54. {
  55. this.prev = pre;
  56. this.next = next;
  57. }
  58. }
  59. }

双向链表:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace _001_线性表
  6. {
  7. /// <summary>
  8. /// 双向链表
  9. /// </summary>
  10. /// <typeparam name="T"></typeparam>
  11. class DoubleLink<T>:IListDS<T>
  12. {
  13. #region IListDS<T> 成员
  14. private DbNode<T> _linkHead;
  15. public DoubleLink()
  16. {
  17. _linkHead = null;
  18. }
  19. public int GetLength()
  20. {
  21. if (IsEmpty()) return 0;
  22. DbNode<T> temp = _linkHead;
  23. int length = 1;
  24. while (temp.Next != null)
  25. {
  26. length++;
  27. temp = temp.Next;
  28. }
  29. return length;
  30. }
  31. public void Clear()
  32. {
  33. _linkHead = null;
  34. }
  35. public bool IsEmpty()
  36. {
  37. return _linkHead == null;
  38. }
  39. /// <summary>
  40. /// 在双向链表的尾端添加一个新数据
  41. /// </summary>
  42. /// <param name="item"></param>
  43. public void Add(T item)
  44. {
  45. DbNode<T> newNode = new DbNode<T>(item);
  46. if (IsEmpty())
  47. {
  48. _linkHead = newNode;
  49. }
  50. else
  51. {
  52. DbNode<T> preNode = GetListItem(this.GetLength() - 1);
  53. newNode.Prev = newNode;
  54. preNode.Next = newNode.Prev;
  55. newNode.Prev = preNode;
  56. }
  57. }
  58. /// <summary>
  59. /// 获取指定位置的双向链表项目,头项从0开始
  60. /// </summary>
  61. public DbNode<T> GetListItem(int index)
  62. {
  63. if (index < 0)
  64. throw new Exception("索引不能小于0");
  65. if (index > this.GetLength() - 1)
  66. throw new Exception("索引超出列表总长度");
  67. DbNode<T> temp = _linkHead;
  68. for (int i = 0; i < index; i++)
  69. {
  70. temp = temp.Next;
  71. }
  72. return temp;
  73. }
  74. /// <summary>
  75. /// 在双向链表指定的位置插入一个新项
  76. /// </summary>
  77. public void Insert(T item, int index)
  78. {
  79. if (index < 0)
  80. throw new Exception("插入位置不能小于0");
  81. if (index > this.GetLength() + 1)
  82. throw new Exception("插入位置超出链表长度");
  83. DbNode<T> newNode = new DbNode<T>(item);
  84. if (index == 0)
  85. {
  86. newNode.Next = _linkHead;
  87. _linkHead = newNode;
  88. }
  89. else
  90. {
  91. DbNode<T> preNode = GetListItem(index - 1); //要插入位置前面的节点
  92. DbNode<T> atfNode = GetListItem(index);//要插入位置后面的节点
  93. preNode.Next = new DbNode<T>(item, preNode, atfNode);
  94. }
  95. }
  96. /// <summary>
  97. /// 删除指定位置的双向链表项
  98. /// </summary>
  99. /// <param name="index"></param>
  100. public T Delete(int index)
  101. {
  102. if (index < 0)
  103. throw new Exception("删除位置不能小于0");
  104. if (index > this.GetLength() - 1)
  105. throw new Exception("插入位置超出链表长度");
  106. T data = default(T);
  107. if (index == 0)
  108. {
  109. data = _linkHead.Data;
  110. _linkHead = _linkHead.Next;
  111. if(!IsEmpty())
  112. this._linkHead.Prev = null;
  113. }
  114. else
  115. {
  116. DbNode<T> DelNode = GetListItem(index); //取到要删除的节点
  117. data = DelNode.Data;
  118. DbNode<T> preNode = DelNode.Prev;
  119. DbNode<T> nextNode = DelNode.Next;
  120. preNode.Next = nextNode;
  121. nextNode.Prev = preNode;
  122. }
  123. return data;
  124. }
  125. public T this[int index]
  126. {
  127. get { return GetEle(index); }
  128. }
  129. public T GetEle(int index)
  130. {
  131. DbNode<T> temp = _linkHead;
  132. for (int i = 0; i < index; i++)
  133. {
  134. temp = temp.Next;
  135. }
  136. return temp.Data;
  137. }
  138. public int Locate(T value)
  139. {
  140. DbNode<T> temp = _linkHead;
  141. if (IsEmpty())
  142. {
  143. return -1;
  144. }
  145. else
  146. {
  147. int index = 0;
  148. while (true)
  149. {
  150. if (!temp.Data.Equals(value))
  151. {
  152. if (temp.Next != null)
  153. {
  154. index++;
  155. temp = temp.Next;
  156. }
  157. else
  158. {
  159. break;
  160. }
  161. }
  162. else
  163. {
  164. return index;
  165. }
  166. }
  167. return -1;
  168. }
  169. }
  170. #endregion
  171. }
  172. }

双向循环链表

从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

双链表的示意图如下:

632293-20170306150003297-951612143.png

表头为空,表头的后继节点为”节点10”(数据为10的节点);”节点10”的后继节点是”节点20”(数据为10的节点),”节点20”的前继节点是”节点10”;”节点20”的后继节点是”节点30”,”节点30”的前继节点是”节点20”;…;末尾节点的后继节点是表头。

双链表删除节点

632293-20170306150039609-1719195275.png

删除”节点30”
删除之前:”节点20”的后继节点为”节点30”,”节点30” 的前继节点为”节点20”。”节点30”的后继节点为”节点40”,”节点40” 的前继节点为”节点30”。
删除之后:”节点20”的后继节点为”节点40”,”节点40” 的前继节点为”节点20”。

双链表添加节点

632293-20170306150105453-2068434988.png

在”节点10”与”节点20”之间添加”节点15”
添加之前:”节点10”的后继节点为”节点20”,”节点20” 的前继节点为”节点10”。
添加之后:”节点10”的后继节点为”节点15”,”节点15” 的前继节点为”节点10”。”节点15”的后继节点为”节点20”,”节点20” 的前继节点为”节点15”。

实现:

ContractedBlock.gif ExpandedBlockStart.gif

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace _001_线性表
  7. {
  8. /// <summary>
  9. /// 双向循环链表
  10. /// </summary>
  11. /// <typeparam name="T"></typeparam>
  12. class DoubleLoopLink<T> : IListDS<T>
  13. {
  14. private DbNode<T> _linkHead;
  15. public T this[int index] =>GetEle(index);
  16. public void Add(T item)
  17. {
  18. DbNode<T> newNode = new DbNode<T>(item, null, null);
  19. if (IsEmpty())
  20. {
  21. _linkHead = newNode;
  22. _linkHead.Prev = _linkHead;
  23. _linkHead.Next = _linkHead;
  24. }
  25. else
  26. {
  27. DbNode<T> preNode = _linkHead;
  28. while (preNode.Next != _linkHead)
  29. {
  30. preNode = preNode.Next;
  31. }
  32. preNode.Next = newNode;//链表的尾部 的后指针 指向新的节点
  33. newNode.SetNode(preNode, _linkHead);
  34. _linkHead.Prev = newNode; //头部的 前指针 指向 新的尾部
  35. }
  36. }
  37. public void Clear()
  38. {
  39. _linkHead = null;
  40. }
  41. public T Delete(int index)
  42. {
  43. T data = default(T);
  44. if (IsEmpty())
  45. throw new Exception("链表为空,没有可清除的项");
  46. if (index < 0 || index > this.GetLength() - 1)
  47. throw new Exception("给定索引超出链表长度");
  48. DbNode<T> preNode = _linkHead;
  49. if (index == 0)
  50. {
  51. while (preNode.Next != _linkHead)
  52. {
  53. preNode = preNode.Next;
  54. }
  55. this._linkHead = _linkHead.Next;
  56. this._linkHead.Prev = preNode;
  57. data = preNode.Next.Data;
  58. preNode.Next = this._linkHead;
  59. }
  60. else
  61. {
  62. for (int i = 1; i < index - 1; i++)
  63. {
  64. preNode = preNode.Next;
  65. }
  66. //看图比较好理解
  67. DbNode<T> aftNode = preNode.Next.Next; //要删除的节点 后面的节点
  68. preNode.Next = aftNode;//要删除节点的前面节点 的后指针 指向 要删除的节点 后面的节点
  69. aftNode.Prev = preNode; //要删除的节点 前面的节点 指向 要删除节点的前面节点
  70. }
  71. return data;
  72. }
  73. public T GetEle(int index)
  74. {
  75. DbNode<T> temp = _linkHead;
  76. for (int i = 0; i < index; i++)
  77. {
  78. temp = temp.Next;
  79. }
  80. return temp.Data;
  81. }
  82. public int GetLength()
  83. {
  84. if (IsEmpty()) return 0;
  85. DbNode<T> temp = _linkHead;
  86. int length = 1;
  87. while (temp.Next != _linkHead)
  88. {
  89. length++;
  90. temp = temp.Next;
  91. }
  92. return length;
  93. }
  94. /// <summary>
  95. /// 插入
  96. /// </summary>
  97. /// <param name="item"></param>
  98. /// <param name="index"></param>
  99. public void Insert(T item, int index)
  100. {
  101. if (IsEmpty())
  102. throw new Exception("数据链表为空");
  103. if (index < 0 || index > this.GetLength())
  104. throw new Exception("给定索引超出链表长度");
  105. DbNode<T> newNode = new DbNode<T>(item);
  106. DbNode<T> preNode = _linkHead;
  107. if (index == 0) //等于零 先找到 链表中 head的前一个节点 这个节点连接 head
  108. {
  109. while (preNode.Next != _linkHead)
  110. {
  111. preNode = preNode.Next;
  112. }
  113. preNode.Next = newNode;
  114. newNode.SetNode(preNode, _linkHead);
  115. _linkHead.Prev = newNode;
  116. return;
  117. }
  118. else
  119. {
  120. for (int i = 1; i < index - 1; i++)
  121. {
  122. preNode = preNode.Next;
  123. }
  124. //preNode要插入位置的前节点
  125. DbNode<T> atfNode = preNode.Next;//要插入节点的后节点
  126. preNode.Next = newNode; //后指针 连上新节点
  127. newNode.SetNode(preNode,atfNode);
  128. atfNode.Prev = newNode;//要插入节点的后节点 连上 新节点
  129. }
  130. }
  131. public bool IsEmpty()
  132. {
  133. return _linkHead == null;
  134. }
  135. public int Locate(T value)
  136. {
  137. if (IsEmpty())
  138. throw new Exception("链表为空");
  139. DbNode<T> preNode = _linkHead;
  140. int index = 0;
  141. while (true)
  142. {
  143. if (!preNode.Data.Equals(value))
  144. {
  145. if (preNode.Next != _linkHead)
  146. {
  147. index++;
  148. preNode = preNode.Next;
  149. }
  150. else
  151. {
  152. break;
  153. }
  154. }
  155. else
  156. {
  157. return index;
  158. }
  159. }
  160. return -1;
  161. }
  162. }
  163. }

基本的链表大概就是这样了。

转载于:https://www.cnblogs.com/rongweijun/p/8072677.html

发表评论

表情:
评论列表 (有 0 条评论,696人围观)

还没有评论,来说两句吧...

相关阅读

    相关 数据结构--双向

    数据结构-链表-双向链表 单向链表和环形链表都是属于拥有方向性的链表,只能单向遍历,如果由于某种原因造成了某个连接断裂,那后面的链表数据便会遗失而无法复原。所以,我们可以