1、源码

Player实体类

  1. package com.study.linkedlist;
  2. public class Player {
  3. public int no;
  4. public String name;
  5. public Player next;
  6. public Player(int no, String name) {
  7. this.no = no;
  8. this.name = name;
  9. }
  10. public Player() {
  11. }
  12. @Override
  13. public String toString() {
  14. return "Player{" +
  15. "no=" + no +
  16. ", name='" + name + '\'' +
  17. '}';
  18. }
  19. }

SingleLinkedList类

  1. package com.study.linkedlist;
  2. import java.util.HashSet;
  3. import java.util.Stack;
  4. public class SingleLinkedList {
  5. //初始化头结点
  6. private Player p = new Player(0,"");
  7. public Player getP() {
  8. return p;
  9. }
  10. //添加节点到链表中
  11. //不考虑编号顺序
  12. //1.找到当前链表的最后一个节点
  13. //2.将最后节点的next指向新的节点
  14. public void add(Player player){
  15. //定义一个零时的头结点
  16. Player temp = p;
  17. //遍历链表,找到最后一个节点
  18. while (true){
  19. if(temp.next == null){
  20. break;
  21. }
  22. temp = temp.next;
  23. }
  24. temp.next=player;
  25. }
  26. //添加方法二:按顺序添加,并且添加编号相同的数据时提示添加错误
  27. public void addByNo(Player player){
  28. //定义一个零时的头结点
  29. Player temp = p;
  30. boolean flag = false;//定义一个标识,判断链表中是否已经存在相同的编号
  31. while (true){
  32. if (temp.next==null){
  33. break;
  34. }
  35. if (temp.next.no > player.no){
  36. break;
  37. }else if (temp.next.no == player.no){
  38. flag = true;//说明编号存在;
  39. break;
  40. }
  41. temp = temp.next;
  42. }
  43. if (flag){
  44. System.out.println("球员已经存在,不能加入"+temp.next.no+temp.next.name);
  45. }else {
  46. player.next = temp.next;
  47. temp.next = player;
  48. }
  49. }
  50. //根据编号修改球员信息
  51. public void updateByNo(Player player){
  52. //判断链表是否为空
  53. if (p.next==null){
  54. System.out.println("链表为空");
  55. return;
  56. }
  57. Player temp = p.next;
  58. boolean flag = false;
  59. while (true){
  60. if(temp.next==null){
  61. break;
  62. }
  63. if(temp.no==player.no){
  64. flag = true;
  65. break;
  66. }
  67. temp = temp.next;
  68. }
  69. if(flag){
  70. temp.name= player.name;
  71. }else {
  72. System.out.println("没有找到改球员");
  73. }
  74. }
  75. //根据编号删除节点
  76. public void deleteByNo(int no){
  77. //判断链表是否为空
  78. if (p.next==null){
  79. System.out.println("链表为空");
  80. return;
  81. }
  82. Player temp = p.next;
  83. boolean flag = false;
  84. while (true){
  85. if(temp.next==null){
  86. break;
  87. }
  88. if(temp.next.no==no){
  89. flag = true;
  90. break;
  91. }
  92. temp = temp.next;
  93. }
  94. if (flag){
  95. temp.next = temp.next.next;
  96. }else {
  97. System.out.println("没有找到改球员");
  98. }
  99. }
  100. //获取链节点的有效个数
  101. public int getLength(Player p){
  102. if (p.next==null){
  103. System.out.println("链表为空");
  104. return 0;
  105. }
  106. int length = 0;
  107. Player temp = p.next;
  108. while (temp!=null){
  109. length++;
  110. temp = temp.next;
  111. }
  112. return length;
  113. }
  114. //查找单链表中倒数第k个节点
  115. public void getByNo(Player p,int no){
  116. if (p.next==null){
  117. System.out.println("链表为空");
  118. return;
  119. }
  120. int l = getLength(p);
  121. if (no<0 || no >l){
  122. System.out.println("没有该节点");
  123. return;
  124. }
  125. Player temp = p.next;
  126. for (int i = 0; i < l - no; i++) {
  127. temp = temp.next;
  128. }
  129. System.out.println("倒数第"+no+"个节点的数据为:"+temp.no+temp.name);
  130. }
  131. //翻转链表
  132. public void reverse(Player p){
  133. if (p.next==null || p.next.next==null){
  134. System.out.println("链表为空");
  135. return;
  136. }
  137. Player reversePlayer = new Player(0,"");
  138. Player temp = p.next;
  139. Player next = null;
  140. while (temp != null){
  141. next = temp.next;
  142. temp.next = reversePlayer.next;
  143. reversePlayer.next =temp;
  144. temp = next;
  145. }
  146. p.next = reversePlayer. next;
  147. }
  148. //从尾到头打印链表
  149. public void reversePrint(Player p){
  150. if (p.next==null || p.next.next==null){
  151. System.out.println("链表为空");
  152. return;
  153. }
  154. Player temp = p.next;
  155. Stack<Player> stack = new Stack<>();
  156. while (temp != null){
  157. stack.push(temp);
  158. temp = temp.next;
  159. }
  160. while (stack.size()>0){
  161. System.out.println(stack.pop());
  162. }
  163. }
  164. //方法一:合并两个有序的单链表(缺陷:使用的addByNo方法,所以相同编号的节点会被删掉一个)
  165. public SingleLinkedList merge(SingleLinkedList sll1,SingleLinkedList sll2){
  166. //判断链表是否为空
  167. if (sll1==null){
  168. System.out.println(sll2);
  169. return null;
  170. }
  171. if (sll2==null){
  172. System.out.println(sll1);
  173. return null;
  174. }
  175. if (sll1==null&&sll2==null){
  176. System.out.println("两个链表都为空");
  177. return null;
  178. }
  179. //获取sll2的头结点
  180. Player p = sll2.getP();
  181. Player temp =p.next;
  182. //定义一个集合,用来存取遍历出来sll2的节点
  183. HashSet<Player> set = new HashSet<>();
  184. //获取sll2的节点的个数
  185. int length = sll2.getLength(p);
  186. //遍历sll2链表,并将其存到集合中
  187. for (int i = 0; i < length; i++) {
  188. set.add(temp);
  189. temp =temp.next;
  190. }
  191. //遍历集合,将其添加的sll1中
  192. for (Player player : set) {
  193. sll1.addByNo(player);
  194. }
  195. return sll1;
  196. }
  197. //方法二:合并两个有序的单链表(遍历两个链表的每个节点,判断节点编号的大小,进行排序,最后将剩余一个不是空的链表插入到最后面)
  198. public SingleLinkedList merge2(SingleLinkedList sll1,SingleLinkedList sll2){
  199. //创建一个新链表
  200. SingleLinkedList sll3 = new SingleLinkedList();
  201. Player p = sll3.getP();//获取新链表的头结点
  202. Player temp = p;//定义一个辅助头结点
  203. //获sll1的头结点
  204. Player p1 = sll1.getP();
  205. Player temp1 = p1.next;
  206. //获sll2的头结点
  207. Player p2 = sll2.getP();
  208. Player temp2 = p2.next;
  209. while (temp1!=null&&temp2!=null){
  210. if(temp1.no>temp2.no){
  211. temp.next=temp2;
  212. temp2 = temp2.next;
  213. }else {
  214. temp.next=temp1;
  215. temp1 = temp1.next;
  216. }
  217. temp = temp.next;
  218. }
  219. temp.next = temp1!=null?temp1:temp2;
  220. return sll3;
  221. }
  222. //显示整个链表
  223. public void show(){
  224. //判断链表是否为空
  225. if(p.next==null){
  226. System.out.println("链表为空");
  227. return;
  228. }
  229. //定义一个辅助头结点
  230. Player temp = p.next;
  231. //遍历链表
  232. while (temp!=null){
  233. System.out.println(temp);
  234. temp = temp.next;
  235. }
  236. }
  237. }

SingleLinkedListDemo测试类

package com.study.linkedlist;

public class SingleLinkedListDemo {

    public static void main(String[] args) {
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.addByNo(new Player(11,"欧文"));
        singleLinkedList.addByNo(new Player(23,"詹姆斯"));
        singleLinkedList.addByNo(new Player(34,"安特托昆博"));
        singleLinkedList.addByNo(new Player(30,"库里"));
        singleLinkedList.addByNo(new Player(24,"科比"));

        int l = singleLinkedList.getLength(singleLinkedList.getP());
        System.out.println("有效的头结点个数为:"+l);
        singleLinkedList.reversePrint(singleLinkedList.getP());
        singleLinkedList.reverse(singleLinkedList.getP());
        singleLinkedList.getByNo(singleLinkedList.getP(),6);
        singleLinkedList.show();
    }

}

部分方法测试结果

图片.png

2、总结

2.1、增加一个节点(增加到链表的最后)

//添加节点到链表中
    //不考虑编号顺序
    //1.找到当前链表的最后一个节点
    //2.将最后节点的next指向新的节点
    public void add(Player player){

        //定义一个零时的头结点
        Player temp = p;
        //遍历链表,找到最后一个节点
        while (true){
            if(temp.next == null){
                break;
            }
            temp = temp.next;
        }
        temp.next=player;
    }

2.2、按顺序增加一个节点

//添加方法二:按顺序添加,并且添加编号相同的数据时提示添加错误
    public void addByNo(Player player){

        //定义一个零时的头结点
        Player temp = p;
        boolean flag = false;//定义一个标识,判断链表中是否已经存在相同的编号
        while (true){
            if (temp.next==null){
                break;
            }
            if (temp.next.no > player.no){
                break;
            }else if (temp.next.no == player.no){
                flag = true;//说明编号存在;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            System.out.println("球员已经存在,不能加入"+temp.next.no+temp.next.name);
        }else {
            player.next = temp.next;
            temp.next = player;
        }
    }

2.3、修改一个节点

//根据编号修改球员信息
    public void updateByNo(Player player){

        //判断链表是否为空
        if (p.next==null){
            System.out.println("链表为空");
            return;
        }
        Player temp = p.next;
        boolean flag = false;
        while (true){
            if(temp.next==null){
                break;
            }
            if(temp.no==player.no){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if(flag){
            temp.name= player.name;
        }else {
            System.out.println("没有找到改球员");
        }
    }

2.4、删除一个节点

//根据编号删除节点
    public void deleteByNo(int no){
        //判断链表是否为空
        if (p.next==null){
            System.out.println("链表为空");
            return;
        }
        Player temp = p.next;
        boolean flag = false;
        while (true){
            if(temp.next==null){
                break;
            }
            if(temp.next.no==no){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            temp.next = temp.next.next;
        }else {
            System.out.println("没有找到改球员");
        }
    }

2.5、获取节点有效个数

//获取链节点的有效个数
    public int getLength(Player p){
        if (p.next==null){
            System.out.println("链表为空");
            return 0;
        }
        int length = 0;
        Player temp = p.next;
        while (temp!=null){
            length++;
            temp = temp.next;
        }
        return length;
    }

2.6、查找链表中倒数第K个节点(重点,leetcode原题)

在已知链表的长度下:

//查找单链表中倒数第k个节点
    public void getByNo(Player p,int no){
        if (p.next==null){
            System.out.println("链表为空");
            return;
        }
        int l = getLength(p);
        if (no<0 || no >l){
            System.out.println("没有该节点");
            return;
        }
        Player temp = p.next;
        for (int i = 0; i < l - no; i++) {
            temp = temp.next;
        }
        System.out.println("倒数第"+no+"个节点的数据为:"+temp.no+temp.name);
    }

链表的长度未知,可采用双指针来查找:

//核心代码
ListNode first = head,last = head;
for(int i=0;i<k;i++){
    if(first==null){
        return null;
    }
    first = first.next;
}
while(first!=null){
    first = first.next;
    last = last.next;
}
return last;

2.7、翻转链表(重点,LeetCode原题)

//翻转链表
public void reverse(Player p){
    if (p.next==null || p.next.next==null){
        System.out.println("链表为空");
        return;
    }
    Player reversePlayer = new Player(0,"");
    Player temp = p.next;
    Player next = null;
    while (temp != null){
        next = temp.next;
        temp.next = reversePlayer.next;
        reversePlayer.next =temp;
        temp = next;
    }
    p.next = reversePlayer. next;
}

2.8、从尾到头打印链表(重点,LeetCode原题)

//从尾到头打印链表
//采用栈的特点
public void reversePrint(Player p){
    if (p.next==null || p.next.next==null){
        System.out.println("链表为空");
        return;
    }
    Player temp = p.next;
    Stack<Player> stack = new Stack<>();
    while (temp != null){
        stack.push(temp);
        temp = temp.next;
    }
    while (stack.size()>0){
        System.out.println(stack.pop());
    }
}

2.9、合并两个有序的链表(重点,leetcode原题)

public SingleLinkedList merge2(SingleLinkedList sll1,SingleLinkedList sll2){
    //创建一个新链表
    SingleLinkedList sll3 = new SingleLinkedList();
    Player p = sll3.getP();//获取新链表的头结点
    Player temp = p;//定义一个辅助头结点
    //获sll1的头结点
    Player p1 = sll1.getP();
    Player temp1 = p1.next;
    //获sll2的头结点
    Player p2 = sll2.getP();
    Player temp2 = p2.next;
    while (temp1!=null&&temp2!=null){
        if(temp1.no>temp2.no){
            temp.next=temp2;
            temp2 = temp2.next;
        }else {
            temp.next=temp1;
            temp1 = temp1.next;
        }
        temp = temp.next;
    }
    temp.next = temp1!=null?temp1:temp2;
    return sll3;
}