• 数据结构——单向循环链表&双向循环链表


    一、单向循环链表

    (一)概念

    • 将单链表尾节点的指针域置为起始节点的地址,而不再是NULL,这样从表中任一节点出发,均可访问到链表中的所有节点

    (二)单向循环链表的结构图

    (三)程序封装单向循环链表 

       1.创建链表类和节点类

    1. //节点的结构
    2. class Cnode {
    3. constructor(data) {
    4. this.data = data
    5. this.next = null
    6. }
    7. }
    8. //链表的结构
    9. class CycleLinkList {
    10. constructor() {
    11. this.head = null
    12. this.length = 0
    13. }
    14. }

      2.单向循环链表的操作(方法) 

       1)append() 向链表尾部添加一个节点

    1. append(ele) {
    2. let newnode = new Cnode(ele)
    3. if(this.head==null){
    4. //空链表
    5. this.head=newnode
    6. newnode.next=this.head
    7. }else{
    8. //非空链表
    9. //需要找到最后一个节点
    10. let current=this.head
    11. while(current.next!=this.head){
    12. current=current.next
    13. }
    14. //找到了current表示最后一个节点
    15. current.next=newnode
    16. newnode.next=this.head
    17. }
    18. this.length++
    19. }

       2)toString()  将链表中的数据连接为字符串

    1. toString(){
    2. let current=this.head,index=0,str=""
    3. while(index<this.length){
    4. str+="-"+current.data
    5. current=current.next
    6. index++
    7. }
    8. return str.slice(1)
    9. }

       3)insert() 向链表中插入元素 

    1. insert(position, ele) {
    2. if (position < 0 || position > this.length || Number.isInteger(position)) {
    3. return false
    4. }
    5. let newnode = new Cnode(ele)
    6. let current = this.head,
    7. index = 0
    8. if (position == 0) {
    9. //在头部插入
    10. if (this.length == 0) {
    11. //空链表
    12. this.head = newnode
    13. newnode.next = this.head
    14. } else {
    15. //非空链表
    16. while (current.next != this.head) {
    17. current = current.next
    18. }
    19. newnode.next = this.head
    20. current.next = newnode
    21. this.head = newnode
    22. }
    23. this.length++
    24. } else if (position == this.length) {
    25. //在尾部插入
    26. this.append(ele)
    27. } else {
    28. //在中间插入
    29. while (index < position - 1) {
    30. current = current.next
    31. index++
    32. }
    33. newnode.next = current.next
    34. current.next = newnode
    35. this.length++
    36. }
    37. }

        4)removeAt() 移除在指定位置的元素

    1. removeAt(position) {
    2. //判断位置是否合法(越界判断)
    3. if (position < 0 || position > this.length - 1 || !Number.isInteger(position)) {
    4. return false
    5. }
    6. //非空链表
    7. let current = this.head,
    8. index = 0
    9. if (position == 0) {
    10. //移除头部
    11. if (this.length == 1) {
    12. //只有一个节点
    13. this.head = null
    14. } else {
    15. //找到最后一个节点 最后一个节点的next指向新头部
    16. while (current.next != this.head) {
    17. current = current.next
    18. }
    19. this.head = this.head.next
    20. current.next = this.head
    21. }
    22. } else {
    23. //移除任意位置(包括末尾)
    24. while (index < position - 1) {
    25. current = current.next
    26. index++
    27. }
    28. current.next = current.next.next
    29. }
    30. this.length--
    31. }

       5)indexOf() 查找指定元素

    1. indexOf(ele) {
    2. let current = this.head,
    3. index = 0
    4. while (index < this.length) {
    5. if (current.data == ele) {
    6. return index
    7. } else {
    8. current = current.next
    9. index++
    10. }
    11. }
    12. return -1
    13. }

        6)remove() 移除指定元素

    1. remove(ele) {
    2. let index = this.indexOf(ele)
    3. this.removeAt(index)
    4. }

    (四)完整代码&操作示例

    1. //节点的结构
    2. class Cnode {
    3. constructor(data) {
    4. this.data = data
    5. this.next = null
    6. }
    7. }
    8. //链表的结构
    9. class CycleLinkList {
    10. constructor() {
    11. this.head = null
    12. this.length = 0
    13. }
    14. //1.append() 向链表尾部添加一个元素
    15. append(ele) {
    16. let newnode = new Cnode(ele)
    17. if (this.head == null) {
    18. //空链表
    19. this.head = newnode
    20. newnode.next = this.head
    21. } else {
    22. //非空链表
    23. //需要找到最后一个节点 最后一个节点的next指向头结点
    24. let current = this.head
    25. while (current.next != this.head) {
    26. //继续往下找
    27. current = current.next
    28. }
    29. //找到了current表示最后一个节点
    30. current.next = newnode
    31. newnode.next = this.head
    32. }
    33. this.length++
    34. }
    35. //2.toString() 将链表中的数据链接为字符串
    36. toString() {
    37. let current = this.head,
    38. index = 0,
    39. str = ""
    40. while (index < this.length) {
    41. str += "-" + current.data
    42. current = current.next
    43. index++
    44. }
    45. return str.slice(1)
    46. }
    47. //3.向链表中插入元素
    48. insert(position, ele) {
    49. if (position < 0 || position > this.length || !Number.isInteger(position)) {
    50. return false
    51. }
    52. let newnode = new Cnode(ele)
    53. let current = this.head,
    54. index = 0
    55. if (position == 0) {
    56. //在头部插入
    57. if (this.length == 0) {
    58. //空链表
    59. this.head = newnode
    60. newnode.next = this.head
    61. } else {
    62. //非空链表
    63. while (current.next != this.head) {
    64. current = current.next
    65. }
    66. newnode.next = this.head
    67. current.next = newnode
    68. this.head = newnode
    69. }
    70. this.length++
    71. } else if (position == this.length) {
    72. //在尾部插入
    73. this.append(ele)
    74. } else {
    75. //在中间插入
    76. while (index < position - 1) {
    77. current = current.next
    78. index++
    79. }
    80. newnode.next = current.next
    81. current.next = newnode
    82. this.length++
    83. }
    84. }
    85. //4.移除在指定位置的元素
    86. removeAt(position) {
    87. //判断位置是否合法(越界判断)
    88. if (position < 0 || position > this.length - 1 || !Number.isInteger(position)) {
    89. return false
    90. }
    91. //非空链表
    92. let current = this.head,
    93. index = 0
    94. if (position == 0) {
    95. //移除头部
    96. if (this.length == 1) {
    97. //只有一个节点
    98. this.head = null
    99. } else {
    100. //找到最后一个节点 最后一个节点的next指向新头部
    101. while (current.next != this.head) {
    102. current = current.next
    103. }
    104. this.head = this.head.next
    105. current.next = this.head
    106. }
    107. } else {
    108. //移除任意位置(包括末尾)
    109. while (index < position - 1) {
    110. current = current.next
    111. index++
    112. }
    113. current.next = current.next.next
    114. }
    115. this.length--
    116. }
    117. //5.查找指定元素
    118. indexOf(ele) {
    119. let current = this.head,
    120. index = 0
    121. while (index < this.length) {
    122. if (current.data == ele) {
    123. return index
    124. } else {
    125. current = current.next
    126. index++
    127. }
    128. }
    129. return -1
    130. }
    131. //6.移除指定元素
    132. remove(ele) {
    133. let index = this.indexOf(ele)
    134. this.removeAt(index)
    135. }
    136. }
    137. let clist = new CycleLinkList()
    138. //链表操作
    139. //在末尾添加元素
    140. for (let i = 0; i < 9; i++) {
    141. clist.append(i)
    142. }
    143. console.log(clist.toString(),"添加了元素")
    144. //在指定位置插入元素
    145. clist.insert(3, "newnode")
    146. console.log(clist.toString(),"在3的位置插入了newnode")
    147. //移除指定位置的元素
    148. clist.removeAt(4)
    149. console.log(clist.toString(),"移除了第4个节点--3")
    150. //查找元素
    151. console.log(clist.indexOf(3),"查找3,已经被移除了所以返回-1")
    152. console.log(clist.indexOf(5),"存在,返回下标")
    153. //移除指定元素
    154. clist.remove(8)
    155. console.log(clist.toString(),"删除了8")

    打印结果:

    二、双向循环链表

    (一)概念

    • 可以从两个方向进行遍历,可以利用中间的一个节点推出下一个节点和上一个节点

    (二)双向循环链表的结构图

    (三)程序封装双向循环链表 

    1.创建链表类和节点类

    1. //节点的结构
    2. class Dnode {
    3. constructor(data) {
    4. this.prev = null;
    5. this.data = data;
    6. this.next = null;
    7. }
    8. }
    9. //链表的结构
    10. class DoubleCycleLinkList {
    11. constructor() {
    12. this.head = null;
    13. this.tail = null;
    14. this.length = 0
    15. }
    16. }

    2.单向循环链表的操作(方法) 

      1)append() 向链表尾部添加一个节点

    1. append(ele) {
    2. let newnode = new Dnode(ele);
    3. if (this.length == 0) { //空链表
    4. this.head = newnode;
    5. this.tail = newnode;
    6. newnode.prev = newnode;
    7. newnode.next = newnode; //自己连自己
    8. } else {
    9. //将新节点连接
    10. newnode.prev = this.tail; //新节点.prev = 尾节点
    11. newnode.next = this.head; //新节点的next指向头结点
    12. //断开原来的指向,重新指向新节点
    13. this.tail.next = newnode; //尾节点.next指向新节点
    14. this.head.prev = newnode; //头结点的prev指向新节点
    15. this.tail = newnode; //将尾节点指向新节点
    16. }
    17. this.length++;
    18. }

      2)insert() 向链表中插入元素 

    1. insert(position, ele) {
    2. // 位置是否合法
    3. if (position < 0 || position > this.length || !Number.isInteger(position)) {
    4. return false
    5. }
    6. let newnode = new Dnode(ele);
    7. if (position == 0) {
    8. //在头部插入
    9. if (this.length == 0) { //空链表
    10. this.head = newnode;
    11. this.tail = newnode;
    12. newnode.prev = this.tail
    13. newnode.next = this.head
    14. } else {
    15. //将新节点连接
    16. newnode.next = this.head; //新节点.next指向头节点
    17. newnode.prev = this.tail; //新节点的prev指向尾结点
    18. //断开原来的指向
    19. this.head.prev = newnode; //头节点.prev指向新节点
    20. this.tail.next = newnode //尾节点的next指向新节点
    21. this.head = newnode; //头节点指向新节点
    22. }
    23. this.length++
    24. } else if (position == this.length) {
    25. //在尾部插入
    26. this.append(ele)
    27. } else {
    28. //在中间任意位置
    29. let current = this.head,
    30. index = 0;
    31. while (index < position - 1) {
    32. current = current.next;
    33. index++;
    34. }
    35. // 1.将新节点连上去
    36. newnode.prev = current;
    37. newnode.next = current.next;
    38. // 2.断开原来的指向
    39. current.next = newnode;
    40. newnode.next.prev = newnode;
    41. this.length++;
    42. }
    43. }

       3)removeAt() 移除在指定位置的元素

    1. removeAt(position) {
    2. //判断位置的合法性(越界判断)
    3. if (position < 0 || position > this.length - 1 || !Number.isInteger(position)) {
    4. return false
    5. }
    6. if (this.length == 0) {
    7. //空链表
    8. return
    9. } else {
    10. if (position == 0) {
    11. //移除头节点
    12. if (this.length == 1) {
    13. this.head = null
    14. this.tail = null
    15. } else {
    16. this.head = this.head.next
    17. this.tail.prev=this.head
    18. this.head.prev = this.head
    19. }
    20. } else if (position == this.length - 1) {
    21. //移除尾结点
    22. this.tail = this.tail.prev
    23. this.tail.next = this.head
    24. this.head.prev=this.tail
    25. } else {
    26. //移除中间任意位置的节点
    27. let current = this.head,
    28. index = 0
    29. while (index < position - 1) {
    30. current = current.next
    31. index++
    32. }
    33. current.next = current.next.next
    34. current.next.prev = current
    35. }
    36. this.length--
    37. }
    38. }

      4)indexOf() 查找指定元素

    1. indexOf(ele) {
    2. let current = this.head,
    3. index = 0
    4. while (index < this.length) {
    5. if (current.data == ele) {
    6. return index
    7. } else {
    8. current = current.next
    9. index++
    10. }
    11. }
    12. return -1
    13. }

       5)remove() 移除指定元素

    1. remove(ele) {
    2. let index = this.indexOf(ele)
    3. this.removeAt(index)
    4. }

      6)正向遍历

    1. forwardString() {
    2. let current = this.head,
    3. index = 0,
    4. str = "";
    5. while (index < this.length) {
    6. str += "-" + current.data
    7. current = current.next
    8. index++
    9. }
    10. return str.slice(1)
    11. }

      7)反向遍历      

    1. reverseString() {
    2. let current = this.tail,
    3. index = this.length - 1,
    4. str = "";
    5. while (index >= 0) {
    6. str += "-" + current.data
    7. current = current.prev
    8. index--
    9. }
    10. return str.slice(1)
    11. }

    (四)完整代码&操作示例

    1. //节点的结构
    2. class Dnode {
    3. constructor(data) {
    4. this.prev = null;
    5. this.data = data;
    6. this.next = null;
    7. }
    8. }
    9. //链表的结构
    10. class DoubleCycleLinkList {
    11. constructor() {
    12. this.head = null;
    13. this.tail = null;
    14. this.length = 0
    15. }
    16. //1.在链表尾部添加元素
    17. append(ele) {
    18. let newnode = new Dnode(ele);
    19. if (this.length == 0) { //空链表
    20. this.head = newnode;
    21. this.tail = newnode;
    22. newnode.prev = newnode;
    23. newnode.next = newnode; //自己连自己
    24. } else {
    25. //将新节点连接
    26. newnode.prev = this.tail; //新节点.prev = 尾节点
    27. newnode.next = this.head; //新节点的next指向头结点
    28. //断开原来的指向,重新指向新节点
    29. this.tail.next = newnode; //尾节点.next指向新节点
    30. this.head.prev = newnode; //头结点的prev指向新节点
    31. this.tail = newnode; //将尾节点指向新节点
    32. }
    33. this.length++;
    34. }
    35. // 2.向链表指定位置插入元素
    36. insert(position, ele) {
    37. // 位置是否合法
    38. if (position < 0 || position > this.length || !Number.isInteger(position)) {
    39. return false
    40. }
    41. let newnode = new Dnode(ele);
    42. if (position == 0) {
    43. //在头部插入
    44. if (this.length == 0) { //空链表
    45. this.head = newnode;
    46. this.tail = newnode;
    47. newnode.prev = this.tail
    48. newnode.next = this.head
    49. } else {
    50. //将新节点连接
    51. newnode.next = this.head; //新节点.next指向头节点
    52. newnode.prev = this.tail; //新节点的prev指向尾结点
    53. //断开原来的指向
    54. this.head.prev = newnode; //头节点.prev指向新节点
    55. this.tail.next = newnode //尾节点的next指向新节点
    56. this.head = newnode; //头节点指向新节点
    57. }
    58. this.length++
    59. } else if (position == this.length) {
    60. //在尾部插入
    61. this.append(ele)
    62. } else {
    63. //在中间任意位置
    64. let current = this.head,
    65. index = 0;
    66. while (index < position - 1) {
    67. current = current.next;
    68. index++;
    69. }
    70. // 1.将新节点连上去
    71. newnode.prev = current;
    72. newnode.next = current.next;
    73. // 2.断开原来的指向
    74. current.next = newnode;
    75. newnode.next.prev = newnode;
    76. this.length++;
    77. }
    78. }
    79. //3.移除指定位置的节点
    80. removeAt(position) {
    81. //判断位置的合法性(越界判断)
    82. if (position < 0 || position > this.length - 1 || !Number.isInteger(position)) {
    83. return false
    84. }
    85. if (this.length == 0) {
    86. //空链表
    87. return
    88. } else {
    89. if (position == 0) {
    90. //移除头节点
    91. if (this.length == 1) {
    92. this.head = null
    93. this.tail = null
    94. } else {
    95. this.head = this.head.next
    96. this.tail.prev=this.head
    97. this.head.prev = this.head
    98. }
    99. } else if (position == this.length - 1) {
    100. //移除尾结点
    101. this.tail = this.tail.prev
    102. this.tail.next = this.head
    103. this.head.prev=this.tail
    104. } else {
    105. //移除中间任意位置的节点
    106. let current = this.head,
    107. index = 0
    108. while (index < position - 1) {
    109. current = current.next
    110. index++
    111. }
    112. current.next = current.next.next
    113. current.next.prev = current
    114. }
    115. this.length--
    116. }
    117. }
    118. //4.查找指定元素的位置
    119. indexOf(ele) {
    120. let current = this.head,
    121. index = 0
    122. while (index < this.length) {
    123. if (current.data == ele) {
    124. return index
    125. } else {
    126. current = current.next
    127. index++
    128. }
    129. }
    130. return -1
    131. }
    132. //5.移除指定元素
    133. remove(ele) {
    134. let index = this.indexOf(ele)
    135. this.removeAt(index)
    136. }
    137. //6.正向遍历
    138. forwardString() {
    139. let current = this.head,
    140. index = 0,
    141. str = "";
    142. while (index < this.length) {
    143. str += "-" + current.data
    144. current = current.next
    145. index++
    146. }
    147. return str.slice(1)
    148. }
    149. //7.反向遍历
    150. reverseString() {
    151. let current = this.tail,
    152. index = this.length - 1,
    153. str = "";
    154. while (index >= 0) {
    155. str += "-" + current.data
    156. current = current.prev
    157. index--
    158. }
    159. return str.slice(1)
    160. }
    161. }
    162. let clist = new DoubleCycleLinkList()
    163. //向链表尾部添加元素
    164. for (let i = 0; i < 9; i++) {
    165. clist.append(i)
    166. }
    167. console.log(clist.forwardString(),"向链表尾部添加元素后的链表")
    168. //向链表中的3的位置插入元素
    169. clist.insert(3,"newnode")
    170. console.log(clist.forwardString(),"插入元素后的链表")
    171. //移除指定位置的元素
    172. clist.removeAt(5)
    173. console.log(clist.forwardString(),"移除位置为5的元素(4)的链表")
    174. //查找指定元素
    175. console.log(clist.indexOf(4),"4已经被移除,不存在返回-1")
    176. console.log(clist.indexOf(6),"6存在返回下标")
    177. //移除指定元素
    178. clist.remove(8)
    179. console.log(clist.reverseString(),"移除元素8后的反向遍历的链表")

    打印结果:

  • 相关阅读:
    力扣(LeetCode)42. 接雨水(C++)
    Python3 + Appium + 安卓模拟器实现APP自动化测试并生成测试报告
    力扣20-有效的括号——栈实现
    【C++】构造函数初始化列表 ① ( 类对象作为成员变量时的构造函数问题 | 构造函数初始化列表语法规则 )
    数学术语之源——平凡(trivial)与非平凡(nontrivial)
    剪辑过程中的思考与总结(持续更新ing)
    leetcode200题模式总结
    uniapp 选择地址
    进程间通信--信号
    软件安全性测试要点有哪些?常用软件安全测试工具分享
  • 原文地址:https://blog.csdn.net/qq_56668869/article/details/126498355