【数据结构和算法】第七锻造,链表真身

x33g5p2x  于2021-12-07 转载在 其他  
字(5.5k)|赞(0)|评价(0)|浏览(422)

一、前言

二、链表的简介

三、单向链表的API设置

代码实现

结点类:链表的设置结点类少不了

成员变量和构造方法

清空链表,链表的长度,链表是否为空

获取指定位置处的元素

插入元素t(在链表的最后以结点后插入元素)

在指定i处,添加元素t

删除指定位置i处的元素并返回被删除的元素

查找元素t在链表中第一次出现的位置

提供一个遍历的方法,实现Iterable接口

全部代码概览:

测试类下:

运行效果图: 

四、鲁迅说:一个是关于head.next,另一个也是head.next

一、前言

链表是一个和数组不一样的存储方式。我们都知道数组的存储地址是连续的,这样就不能很好的利

用好内存空间,而链表就解决了这个问题,链表是一存储地址不连续的的存储结构,这样的好处

就是能节省空间。

二、链表的简介

链表是由一系列的结点构成的,链表的第一个元素为头结点,头结点的特点是;不存放具体的数

表示单链表的表头,比如要找一个结点就是从头结点一个一个往下找的。 

每一个结点有一个类似于指针的next,用来指向下一个结点,和一个date区域用于存储数据

头结点不存放数据,最后一个结点不指向null。

三、单向链表的API设置

 代码实现

  1. //定义节点类(成员内部类)
  2. private class Node{
  3. //存储数据
  4. T item;
  5. //下一个节点
  6. Node next;
  7. public Node(T item,Node next){
  8. this.item=item;
  9. this.next=next;
  10. }
  11. }
  1. //记录头节点
  2. private Node head;
  3. //记录链表的长度
  4. private int N;
  5. //构造方法用来初始化成员变量
  6. public LinkList(){
  7. this.head=new Node(null,null);
  8. this.N=0;
  9. }
  1. //方法1:清空链表
  2. public void clear(){
  3. head.next=null;//将头结点的指向置空
  4. this.N=0;//元素个数变为0
  5. }
  6. //方法2:链表的长度
  7. public int length(){
  8. return N;//N就是链表长度
  9. }
  10. //方法3:判断链表是否为空
  11. public boolean isEmpty(){
  12. return this.N==0;//只需判断N是否为0即可
  13. }
  1. //方法4:获取指定位置处的元素
  2. public T get(int i){
  3. Node node=head.next;//node是下一个结点
  4. if(node!=null){//有下一个结点
  5. for(int index=0;index<i;index++){
  6. node=node.next;//往下一个结点移动
  7. }
  8. return node.item;
  9. }
  10. return null;
  11. }
  1. //方法5:插入元素t(在链表的最后以结点后插入元素)
  2. public void insert(T t){
  3. //创建一个结点
  4. Node node=head;
  5. while(node.next!=null){//找到最后一个结点的前一个结点
  6. node=node.next;
  7. }
  8. Node newLast=new Node(t, null);
  9. //之前的最后指向现在的最后结点
  10. node.next=newLast;
  11. //元素个数加一
  12. N++;
  13. }
  1. //方法6:在指定i处,添加元素t
  2. public void insert(int i,T t){
  3. //创建一个结点,从头结点开始
  4. Node node =head;
  5. for(int index=0;index<i;index++){//找到i位置处的前一个元素
  6. node=node.next;
  7. }
  8. //当前i位置的结点
  9. Node oldNode=node.next;
  10. //创建结点t
  11. Node newNode=new Node(t, null);
  12. //此时node表示的还是前一个结点,所以只需要把前一个结点指向创建的新结点
  13. node.next=newNode;
  14. //新结点指向原来i位置处的结点,即可完成连接
  15. newNode.next=oldNode;
  16. //元素个数加一
  17. N++;
  18. }
  1. //方法7:删除指定位置i处的元素并返回被删除的元素
  2. public T remove(int i) {
  3. //创建一个结点,从头节点开始
  4. Node node=head;
  5. //因为是从头结点开始的,所以下面循环会找到i位置的前一个结点
  6. for(int index=0;index<i;index++){
  7. node=node.next;
  8. }
  9. //i位置处的结点
  10. Node iNode=node.next;
  11. //直接让i位置处的前以结点指向i位置的后一结点就可以删除i位置处的结点
  12. node.next=iNode.next;//或者也可以node.next=node.next.next;
  13. //元素减1
  14. N--;
  15. return iNode.item;
  16. }
  1. //方法8:查找元素t在链表中第一次出现的位置
  2. public int indexOf(T t){
  3. Node node=head;
  4. for(int index=0;node.next!=null;index++){
  5. node=node.next;
  6. if(node.item.equals(t)){
  7. return index;
  8. }
  9. }
  10. //找不到
  11. return -1;
  12. }
  1. public class LinkList<T> implements Iterable{}
  1. //实现Iterable接口,重写iterator方法
  2. @Override
  3. //因为要的接口对象(接口不能直接new),所以我们必须创建一个对象去实现这个接口
  4. public Iterator iterator() {
  5. return new LIterator() ;
  6. }
  7. public class LIterator implements Iterator{
  8. //实现Iterator接口重写hasNext()和next()两个方法
  9. private Node n;
  10. public LIterator(){
  11. this.n=head;//从头结点开始
  12. }
  13. @Override
  14. public boolean hasNext() {//是否有元素
  15. return n.next!=null;
  16. }
  17. @Override
  18. public Object next() {//返回下一个元素
  19. n=n.next;
  20. return n.item;
  21. }
  22. }

全部代码概览:

  1. import java.util.Iterator;
  2. public class LinkList<T> implements Iterable{
  3. //定义节点类
  4. private class Node{
  5. //存储数据
  6. T item;
  7. //下一个节点
  8. Node next;
  9. public Node(T item,Node next){
  10. this.item=item;
  11. this.next=next;
  12. }
  13. }
  14. //记录头节点
  15. private Node head;
  16. //记录链表的长度
  17. private int N;
  18. //构造方法用来初始化成员变量
  19. public LinkList(){
  20. this.head=new Node(null,null);
  21. this.N=0;
  22. }
  23. //方法1:清空链表
  24. public void clear(){
  25. head.next=null;//将头结点的指向置空
  26. this.N=0;//元素个数变为0
  27. }
  28. //方法2:链表的长度
  29. public int length(){
  30. return N;//N就是链表长度
  31. }
  32. //方法3:判断链表是否为空
  33. public boolean isEmpty(){
  34. return this.N==0;//只需判断N是否为0即可
  35. }
  36. //方法4:获取指定位置处的元素
  37. public T get(int i){
  38. Node node=head.next;//node是下一个结点
  39. if(node!=null){//有下一个结点
  40. for(int index=0;index<i;index++){
  41. node=node.next;//往下一个结点移动
  42. }
  43. return node.item;
  44. }
  45. return null;
  46. }
  47. //方法5:插入元素t(在链表的最后以结点后插入元素)
  48. public void insert(T t){
  49. //创建一个结点
  50. Node node=head;
  51. while(node.next!=null){//找到最后一个结点的前一个结点
  52. node=node.next;
  53. }
  54. Node newLast=new Node(t, null);
  55. //之前的最后指向现在的最后结点
  56. node.next=newLast;
  57. //元素个数加一
  58. N++;
  59. }
  60. //方法6:在指定i处,添加元素t
  61. public void insert(int i,T t){
  62. //创建一个结点,从头结点开始
  63. Node node =head;
  64. for(int index=0;index<i;index++){//找到i位置处的前一个元素
  65. node=node.next;
  66. }
  67. //当前i位置的结点
  68. Node oldNode=node.next;
  69. //创建结点t
  70. Node newNode=new Node(t, null);
  71. //此时node表示的还是前一个结点,所以只需要把前一个结点指向创建的新结点
  72. node.next=newNode;
  73. //新结点指向原来i位置处的结点,即可完成连接
  74. newNode.next=oldNode;
  75. //元素个数加一
  76. N++;
  77. }
  78. //方法7:删除指定位置i处的元素并返回被删除的元素
  79. public T remove(int i) {
  80. //创建一个结点,从头节点开始
  81. Node node=head;
  82. //因为是从头结点开始的,所以下面循环会找到i位置的前一个结点
  83. for(int index=0;index<i;index++){
  84. node=node.next;
  85. }
  86. //i位置处的结点
  87. Node iNode=node.next;
  88. //直接让i位置处的前以结点指向i位置的后一结点就可以删除i位置处的结点
  89. node.next=iNode.next;//或者也可以node.next=node.next.next;
  90. //元素减1
  91. N--;
  92. return iNode.item;
  93. }
  94. //方法8:查找元素t在链表中第一次出现的位置
  95. public int indexOf(T t){
  96. Node node=head;
  97. for(int index=0;node.next!=null;index++){
  98. node=node.next;
  99. if(node.item.equals(t)){
  100. return index;
  101. }
  102. }
  103. //找不到
  104. return -1;
  105. }
  106. //实现Iterable接口,重写iterator方法
  107. @Override
  108. //因为要的接口对象(接口不能直接new),所以我们必须创建一个对象去实现这个接口
  109. public Iterator iterator() {
  110. return new LIterator() ;
  111. }
  112. public class LIterator implements Iterator{
  113. //实现Iterator接口重写hasNext()和next()两个方法
  114. private Node n;
  115. public LIterator(){
  116. this.n=head;//从头结点开始
  117. }
  118. @Override
  119. public boolean hasNext() {//是否有元素
  120. return n.next!=null;
  121. }
  122. @Override
  123. public Object next() {//返回下一个元素
  124. n=n.next;
  125. return n.item;
  126. }
  127. }
  128. }

测试类下:

  1. public class LinkListText {
  2. public static void main(String[] args) {
  3. //创建链表对象
  4. LinkList<String> list=new LinkList<String>();
  5. list.insert("张三");
  6. list.insert("李四");
  7. list.insert("王五");
  8. list.insert("李四");
  9. System.out.println("链表为空吗:"+list.isEmpty());
  10. for(Object s:list){
  11. System.out.println(s);
  12. }
  13. //元素个数
  14. System.out.println("初始元素个数:"+list.length());
  15. System.out.println("----------------------");
  16. //插入
  17. list.insert(1,"赵六");
  18. list.insert(2,"历七");
  19. //元素个数
  20. System.out.println("插入后元素个数:"+list.length());
  21. //第一次出现的位置
  22. System.out.println("张三第一次出现的位置:"+list.indexOf("张三"));
  23. System.out.println("----------------------");
  24. for(Object s:list){
  25. System.out.println(s);
  26. }
  27. //清除链表
  28. list.clear();
  29. System.out.println("清除后,链表为空吗:"+list.isEmpty());
  30. }
  31. }

运行效果图: 

四、鲁迅说:一个是关于head.next,另一个也是head.next

有关于左右边的.next解读:

** 左边的.next表示的是指向,右边的.next表示的下一个元素。**

一般来说在左边的是指向,在右边的是下一个元素。(这里.next前可以是任意非null结点)

head.next!=null一样的道理。

相关文章