当前位置:   article > 正文

数据结构——双向链表、循环链表_java有哪些双向链表和双向循环链表

java有哪些双向链表和双向循环链表

目录

双链表的实现                                                                                                     

java中LinkedList实现

链表的复杂度分析

循环链表


双向链表,它由多个结点组成,每个结点都由一个数据域和两个指针域组成,数据域用来存储数据,其中一个指针域用来指向其后继结点,另一个指针域用来指向前驱结点。链表的头结点的数据域不存储数据,指向前驱结点的指针域值为null,指向后继结点的指针域指向第一个真正存储数据的结点。

双链表的实现                                                                                                     

                                                                                                          结点API设计

类名Node
构造方法Node(T t,Node pre,Node next)
成员变量

T item :存储数据

Node pre:指向上一个结点

Node next:指向下一个结点

                                                                                                        双向链表API设计

类名LoopLinkList
构造方法LoopLinkList():创建对象
成员方法

1.public void clear():清空线性表

2.public boolean isEmpty():判断线性表是否为空

3.public int length():获取线性表中元素的个数

4.public  T get(int i)获取第i个元素的值

5.public void insert(T t):在线性表中添加一个元素

6.public void insert(int i,T t):在第i个元素之前插入一个值为t的元素

7.public T remove(int i):删除第i个数据元素

8.public int indexOf(T t):返回线性表中首次出现该元素的索引值
9.public T getFirst():获取第一个元素

10.public T getLast():获取最后一个元素

成员内部类private class Node:结点类
成员变量

1.private Node first:记录首结点

2.private Node last:记录尾结点

3.private int N:记录链表的长度

  1. public class LoopLinkList<T> implements Iterable<T>{
  2. public static void main(String[] args) {
  3. // 创建双向链表对象
  4. LoopLinkList<String> sl= new LoopLinkList<>();
  5. // 测试插入
  6. sl.insert("龍弟");
  7. sl.insert("龍龍");
  8. sl.insert("龍哥");
  9. sl.insert(1,"龍帝");
  10. for(String s: sl){
  11. System.out.println(s);
  12. }
  13. System.out.println("-----------------");
  14. // 测试获取
  15. String getResult = sl.get(1);
  16. System.out.println("获取索引1处的结果为:"+getResult);
  17. // 测试删除
  18. String removeResult = sl.remove(0);
  19. System.out.println("删除的元素:" + removeResult);
  20. System.out.println("---------------------");
  21. System.out.println("第一个元素是"+sl.getFirst());
  22. System.out.println("最后一个元素是:" + sl.getLast());
  23. // 测试清空
  24. sl.clear();
  25. System.out.println("清空后的线性表中的元素个数为:"+sl.length());
  26. }
  27. //首结点
  28. private Node head;
  29. // 最后一个结点
  30. private Node last;
  31. //链表的长度
  32. private int N;
  33. // 结点类
  34. private class Node {
  35. public Node(T item, Node pre, Node next) {
  36. this.item = item;
  37. this.pre = pre;
  38. this.next = next;
  39. }
  40. //存储数据
  41. public T item;
  42. // 指向上一个结点
  43. public Node pre;
  44. // 指向下一个结点
  45. public Node next;
  46. }
  47. public LoopLinkList() {
  48. //初始化头节点和尾结点
  49. this.head = new Node(null, null, null);
  50. this.last = null;
  51. // 初始化元素结点
  52. this.N = 0;
  53. }
  54. // 清空链表
  55. public void clear() {
  56. this.head.next = null;
  57. this.head.item = null;
  58. this.last = null;
  59. this.N = 0;
  60. }
  61. // 获取链表长度
  62. public int length() {
  63. return N;
  64. }
  65. // 判断链表是否为空
  66. public boolean isEmpty() {
  67. return N == 0;
  68. }
  69. // 获取第一个元素
  70. public T getFirst() {
  71. if (isEmpty()) {
  72. return null;
  73. }
  74. return head.next.item;
  75. }
  76. // 获取最后一个元素
  77. public T getLast() {
  78. if (isEmpty()) {
  79. return null;
  80. }
  81. return last.item;
  82. }
  83. // 插入元素t
  84. public void insert(T t) {
  85. // 如果链表为空
  86. if (isEmpty()) {
  87. // 创建新的节点
  88. Node newNode = new Node(t, head, null);
  89. // 让新结点成为尾结点
  90. last = newNode;
  91. // 让头结点指向尾结点
  92. head.next = last;
  93. } else {
  94. // 如果链表不为空
  95. Node oldLast = last;
  96. // 创建新的结点
  97. Node newNode = new Node(t, oldLast, null);
  98. // 让当前的尾节点 指向新结点
  99. oldLast.next = newNode;
  100. // 让新结点成为尾结点
  101. last = newNode;
  102. }
  103. N++;
  104. }
  105. //向指定位置i处插入元素t
  106. public void insert(int i, T t) {
  107. //找到位置i的前一个结点
  108. Node pre = head;
  109. for (int index = 0; index < i; index++ ){
  110. pre = pre.next;
  111. }
  112. //当前结点
  113. Node curr = pre.next;
  114. //构建新节点
  115. Node newNode = new Node(t, pre, curr);
  116. pre.next = newNode;
  117. curr.pre = newNode;
  118. //长度+1
  119. N++;
  120. }
  121. // 获取指定位i处的元素
  122. public T get(int i){
  123. Node n = head.next;
  124. for(int index = 0; index < i; index++){
  125. n = n.next;
  126. }
  127. return n.item;
  128. }
  129. // 找到元素t在链表中第一次出现的位置
  130. public int indexOf(T t){
  131. Node n = head;
  132. for(int index = 0; index<N; index++){
  133. n = n.next;
  134. if(n.next.equals(t)){
  135. return index;
  136. }
  137. }
  138. return -1;
  139. }
  140. // 删除位置i处的元素,并返回该元素
  141. public T remove(int i){
  142. //寻找i位置的前一个元素
  143. Node pre = head;
  144. for(int index = 0; index < i; index++){
  145. pre = pre.next;
  146. }
  147. //i位置的元素
  148. Node curr = pre.next;
  149. //i位置的下一个元素
  150. Node nextNode = curr.next;
  151. pre.next = nextNode;
  152. nextNode.pre = pre;
  153. // 长度减一
  154. N--;
  155. return curr.item;
  156. }
  157. @Override
  158. public Iterator<T> iterator() {
  159. return new TIterator();
  160. }
  161. private class TIterator implements Iterator{
  162. private Node n;
  163. public TIterator(){
  164. this.n = head;
  165. }
  166. @Override
  167. public boolean hasNext() {
  168. return n.next != null;
  169. }
  170. @Override
  171. public Object next() {
  172. n = n.next;
  173. return n.item;
  174. }
  175. }
  176. }

java中LinkedList实现

java中LinkedList集合也是使用双向链表实现,并提供了增删改查等相关方法

1.底层是否用双向链表实现;
2.结点类是否有三个域

链表的复杂度分析

get(int i):每一次查询,都需要从链表的头部开始,依次向后查找,随着数据元素N的增多,比较的元素越多,时间复杂度为O(n)
insert(int i,T t);每一次插入,需要先找到i位置的前一个元素,然后完成插入操作,随着数据元素N的增多,查找的元素越多,时间复杂度为O(n);
remove(int i):每一次移除,需要先找到i位置的前一个元素,然后完成插入操作,随着数据元素N的增多,查找的元素越多,时间复杂度为O(n)
相比较顺序表,链表插入和删除的时间复杂度虽然一样,但仍然有很大的优势,因为链表的物理地址是不连续的,它不需要预先指定存储空间大小,或者在存储过程中涉及到扩容等操作..同时它并没有涉及的元素的交换。
相比较顺序表,链表的查询操作性能会比较低。因此,如果我们的程序中查询操作比较多,建议使用顺序表;增删操作比较多,建议使用链表。

循环链表

循环链表,也就是链表整体要形成一个圆环状。在单向链表中,最后一个节点的指针为null ,不指向任何结点,因为没有下一个元素了。要实现循环链表,我们只需要让单向链表的最后一个节点的指针指向头结点即可。

 

  1. public static void main(String[] args) {
  2. //构建结点
  3. Node<Integer> first=new Node<Integer>(5,null);
  4. Node<Integer> second=new Node<Integer>(6,null);
  5. Node<Integer> third=new Node<Integer>(7,null);
  6. Node<Integer> fourth=new Node<Integer>(7,null);
  7. Node<Integer> fifth=new Node<Integer>(7,null);
  8. //生成单链表
  9. first.next=second;
  10. second.next=third;
  11. third.next=fourth;
  12. fourth.next=fifth;
  13. //构成循环链表,让最后一个结点指向第一个结点
  14. fifth.next=first;
  15. }

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

闽ICP备14008679号