编码技巧之循环【笔记】

编码技巧之循环【笔记】

循环控制

在循环中要定义一个循环不变式

循环不变式是一句断言定义各变量所满足的条件

与递归不同,在递归里面断言就是证明一个函数,而在循环中,是没法直接看到的,是心中默认的一个条件

循环的书写方法

定义一个循环不变式,并在循环体每次结束后保持循环不变式

和递归一样,先一般情况,然后再特殊情况

每次必须向前推进循环不变式中涉及的变量值,且每次推进的规模不能多,必须为1

例题一:链表反转

将1->2->3->4->5->null变成null<-1<-2<-3<-4<-5

与递归的想法不同,循环的话不能将第一个单独提出来,因为这样要考虑很多的边界问题,因此可以在链表中间切一刀,将前三个反转以后可以发现就是头和尾变化了,此时可以设置两个变量来维持

其中newhead指向反转成功的链表,currenthead指向还没有成功反转的链表,这就是循环不变式,每次循环都必须遵守,推进以后

只要当newhead从null移动到5的时候,currenthead移动到null的时候,就可以确定整个链表反转完成了

具体代码如下:

package interview.loop;

import java.util.ArrayList;
import java.util.Arrays;

import interview.common.Node;
import interview.recursion.LinkedListCreator;

public class LinkedListReverser {

  public <T> Node<T> reverseLinkedList(Node<T> head) {
    Node<T> newHead = null;
    Node<T> curHead = head;
    // Loop invariant:
    // newHead points to the linked list already reversed.
    // curHead points to the linked list not yet reversed.

    // Loop invariant holds.
    while(curHead != null) {
      // Loop invariant holds.
      Node<T> next = curHead.getNext();
      curHead.setNext(newHead);
      newHead = curHead;
      curHead = next;
      // Loop invariant holds.
    }
    // Loop invariant holds.
    return newHead;
  }

  public static void main(String[] args) {
    LinkedListCreator creator = new LinkedListCreator();
    LinkedListReverser reverser = new LinkedListReverser();

    Node.printLinkedList(reverser.reverseLinkedList(
        creator.createLinkedList(new ArrayList<>())));

    Node.printLinkedList(reverser.reverseLinkedList(
        creator.createLinkedList(Arrays.asList(1))));

    Node.printLinkedList(reverser.reverseLinkedList(
        creator.createLinkedList(Arrays.asList(1, 2, 3, 4, 5))));
    System.out.println("done");
  }
}

例题二:链表中的节点删除(delete_if)

将1->2->3->2->5->null中的所有数值为2的节点全部删除,删除以后变为1->3->5->null

设置一个变量previous指向对应的节点,在删除后面的节点以后previous不需要移动,不然在遇到两个连续的需要删除的节点的时候会错过一个

循环不变式是要保证所有的数值为2的节点能够被正确的删除

如果头结点没有previous怎么办?

进行特殊处理或者增加虚拟的头结点

具体代码如下:

package interview.loop;

import java.util.ArrayList;
import java.util.Arrays;

import interview.common.Node;
import interview.recursion.LinkedListCreator;

public class LinkedListDeletor {

  public <T> Node<T> deleteIfEquals(Node<T> head, T value) {
    while (head != null && head.getValue() == value) {
      head = head.getNext();
    }

    if (head == null) {
      return null;
    }

    Node<T> prev = head;
    // Loop invariant: list nodes from head up to prev has been
    // processed. (Nodes with values equal to value are deleted.)
    while(prev.getNext() != null) {
      if (prev.getNext().getValue() == value) {
        // delete it
        prev.setNext(prev.getNext().getNext());
      } else {
        prev = prev.getNext();
      }
    }

    return head;
  }

  public static void main(String[] args) {
    LinkedListCreator creator = new LinkedListCreator();
    LinkedListDeletor deletor = new LinkedListDeletor();
    Node.printLinkedList(deletor.deleteIfEquals(
        creator.createLinkedList(Arrays.asList(1, 2, 3, 2, 5)),
        2));
    Node.printLinkedList(deletor.deleteIfEquals(
        creator.createLinkedList(Arrays.asList(1, 2, 3, 2, 2)),
        2));
    Node.printLinkedList(deletor.deleteIfEquals(
        creator.createLinkedList(Arrays.asList(1, 2, 3, 2, 2)),
        1));
    Node.printLinkedList(deletor.deleteIfEquals(
        creator.createLinkedList(Arrays.asList(2, 2, 3, 2, 2)),
        2));
    Node.printLinkedList(deletor.deleteIfEquals(
        creator.createLinkedList(Arrays.asList(2, 2, 2, 2, 2)),
        2));
    Node.printLinkedList(deletor.deleteIfEquals(
        creator.createLinkedList(Arrays.asList(2)),
        2));
    Node.printLinkedList(deletor.deleteIfEquals(
        creator.createLinkedList(Arrays.asList(2)),
        1));
    Node.printLinkedList(deletor.deleteIfEquals(
        creator.createLinkedList(new ArrayList<Integer>()),
        1));
  }
}

感谢观看,文笔有限,博客不出彩,还请多多见谅
原文地址:https://www.cnblogs.com/jokingremarks/p/14468515.html