当前位置:   article > 正文

Java 单向列表的几种操作方式(删除,查找环,环入口)_嵌入式单向列表的操作方式

嵌入式单向列表的操作方式

Java ⼆叉树操作

本文章的列表为单项列表。

列表的节点类,类的内容包括数据int 和 下一个节点的指向。

  1. class Node{
  2. int data;
  3. Node next;
  4. public Node(int data,Node next) {
  5. this.data = data;
  6. this.next = next;
  7. }
  8. }

1.删除节点操作

     1.1是头节点为空

   1.2删除节点在链表的尾部,即删除p4

   1.3删除节点在链表的中间位置 即删除

对应的Java代码如下:

  1. public static void deleteNode(Node head, Node node) {
  2. if (head == node) {
  3. head = null;
  4. } else if (node.next == null) {
  5. while (head.next != node)
  6. {
  7. head = head.next;
  8. }
  9. head.next = null;
  10. } else {
  11. Node q = node.next;
  12. node.data = q.data;
  13. node.next = q.next;
  14. }
  15. }

 2.删除指定数值的节点

  2.1方案一:将数值data不等于num的节点存放到栈中,然后拿到栈的队列,然后进行出栈操作返         回头节点。如图删除data是3的节点。

对应代码

  1. public Node removeValue(Node head,int num) {
  2. Stack<Node> stack = new Stack<>();
  3. while (head != null) {
  4. if (head.data != num) {
  5. stack.push(head);
  6. }
  7. head = head.next;
  8. }
  9. while (!stack.isEmpty()) {
  10. stack.peek().next = head;
  11. head = stack.pop();
  12. }
  13. return head;
  14. }

2.2 方案二: 首先判断要删除的数字是否在节点的前几位,如果在节点的头几位,先遍历到要返回的头节点,如果删除的节点,不在头节点,就进行遍历删除操作。图片是删除数值1的节点,head指向了p2 ,之后的节点用过链表遍历删除。

  1. public Node removeValue2(Node head,int num) {
  2. while(head != null) {
  3. if (head.data != num) {
  4. break;
  5. }
  6. head = head.next;
  7. }
  8. Node pre = head;
  9. Node cur = head;
  10. while (cur != null) {
  11. if (cur.data != num) {
  12. pre.next = cur.next;
  13. } else {
  14. cur = pre;
  15. }
  16. cur = cur.next;
  17. }
  18. return head;
  19. }

3.删除重复节点:

方案是利用HasSet的存值不可重复性,开始存储节点的值,如果节点的值在HashSet中存在,即表明此值是重复值。
 

  1. public void deleteDuplication(Node head) {
  2. if (head == null) {
  3. return;
  4. }
  5. HashSet<Integer> set = new HashSet<>();
  6. Node pre = head;
  7. Node cur = head.next;
  8. set.add(head.data);
  9. while (cur != null) {
  10. if (set.contains(cur.data)) {
  11. pre.next = cur.next;
  12. } else {
  13. set.add(cur.data);
  14. pre = cur;
  15. }
  16. cur = cur.next;
  17. }
  18. }

4.检查列表是否有环

  假设链表是一个有环链表,且由P4指向P2构成环。那么  使用两个指针   S 和 L,

 让两指针同时向后遍历  而且L的遍历速度是S的两倍,呢么如果是有环的话,

 S终究会追上L。因此我们可以 以SL是否相遇作为判    断是否有环的必要条件。

如图中的案例,SL在第散步相遇。证明有环的存在

  1. public boolean isLoop(Node head){
  2. // TODO 定义两个指针,分别是S和L
  3. Node L= first;
  4. Node S= first;
  5. // TODO 遍历一遍链表,如果最后是null的话就代表没有环
  6. while ( L != null && L.next != null){
  7. L = L.next.next;
  8. S = S.next;
  9. //如果俩相遇了,代表有环
  10. if (L == S){
  11. return true;
  12. }
  13. }
  14. return false;
  15. }

5.检查查找单列表否的入口

 如图所展示,这是一个有环列表的模型,S、L分别指向头节点,P为环的入口点,K为上个方法查询链表是否为环的相遇点。

接下来我们将环列表由P也就是环的入口处拆开成一条直线进行查看 

 我们将链表分为几个线段,分别是 ,a 是链表头到环入口的长度,b是环入口到S L相遇点的长度,c是相遇点再到P的长都,d是P到P环的长度

我们在查找链表是否是环的问题上利用的是 S走过的长度是L的二倍, 也就是说相同时间 S和L相遇的时候 S的路程是L的路程的两倍。

可得出如下结论:

2 * (a + b) = n * d +b +a ; 其中 n指的是 S节点在列表里面由P到P循环走过的次数 >=1; 

由于 b = d - c;

a +d - c =n * d 

a = c + (n-1) * d

所以 a和c 是差了 (n-1) * d 个 而d就是 p到p的距离,因为n必须是正整数所以 正整数  (n-1) * d可以忽略不计

等式就变成了

a = c

所以要是闭环的情况下S走过P 和L从头节点走过P时必定相遇。

我们将L重新放到头节点然后 将S从相遇节点往后遍历, 当S在 环中循环n次之后,会和L在节点入口处相遇。

具体的代码:

  1. public ListNode detectCycle(ListNode head) {
  2. ListNode S= head;
  3. ListNode L= head;
  4. while(S!= null && S.next != null){
  5. S= S.next.next;
  6. L= L.next;
  7. if(S== L){
  8. break;
  9. }
  10. }
  11. if(S== null || S.next == null){
  12. return null;
  13. }
  14. L= head;
  15. while(S!= slow){
  16. L= L.next;
  17. S= S.next;
  18. }
  19. return L;
  20. }

 

 

 

 

 

 

 

 

 

 

 

 

 

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

闽ICP备14008679号