单链表-交换相邻节点 & 反转链表

定义单链表

class MyLinkedList {
    static class ListNode{
        int val;
        ListNode next;
        public ListNode(int val,ListNode next){
            this.val = val;
            this.next = next;
        }
    }

    ListNode head,tail;
    int size = 0;



    /** Initialize your data structure here. */
    public MyLinkedList() {

    }

    /** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
    public int get(int index) {
        ListNode p = node(index);
        return p.val;
    }

    private ListNode node(int index){
        indexRangeCheck(index);
        ListNode p = head;
        for(int i=0; i<index; i++){
            p = p.next;
        }
        return p;
    }

    /** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
    public void addAtHead(int val) {
       if(size == 0){
           head = new ListNode(val, null);
           tail = head;
       }else {
           //头插入, head指针需要变动, tail不变
           ListNode node = new ListNode(val, head);
           head = node;
       }
       size++;
    }

    /** Append a node of value val to the last element of the linked list. */
    public void addAtTail(int val) {
        if(size == 0){
            head = new ListNode(val, null);
            tail = head;
        }else {
            //尾插入, tail 指针需要变动, head 不变
            ListNode new_tail = new ListNode(val, null);
            tail.next = new_tail;
            tail = new_tail;
        }
        size++;
    }

    /** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
    public void addAtIndex(int index, int val) {
         if(index == 0){
             head = new ListNode(val, null);
             tail = head;
         }else{
             ListNode prev = node(index - 1);
             ListNode add_node = new ListNode(val, prev.next);
             prev.next = add_node;
         }
         size++;
    }

    /** Delete the index-th node in the linked list, if the index is valid. */
    public void deleteAtIndex(int index) {
      indexRangeCheck(index);
      if(index == 0){//删除的是头节点
          head = head.next;
          if(size == 1){
            tail = head;
          }
      }else{
          ListNode prev = node(index - 1);
          if(prev.next.next == null){//待删除结点是最后一个节点
              tail = prev;
          }
          prev.next = prev.next.next;

      }
      size--;
    }

    // check if the given index out of range of the list
    private void indexRangeCheck(int index){
        if (index<0 || index>= size){
            throw new RuntimeException(String.format("index out of range, current index: %s, size of list is: %s", index, size));
        }
    }

//定义toString方法,方便打印
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        ListNode p = this.head;
        while (p != null){
            sb.append(p.val).append(" -> ");
            p = p.next;
        }

        if(sb.length() > 4)
            return sb.substring(0, sb.length()-4);
        else return "list is null";
    }
}

交换相邻节点

算法


public class LinkedListUtils {
  /**
     * list每两个相邻节点交换
     * 为方便说明,用p1,p2代表需要参与交换的节点,此时注意3点:
     *    1 若交换前p1指向list头节点,则p1,p2交换后, 需要将list头节点指针指向p2,使p2成为新的头节点
     *    2 若p1,p2交换前,p1的前驱节点为prev, 则p1, p2交换后, 需要让prev变更成为p2的前驱节点
     *    3 若p1,p2交换前,p1的后继节点为next, 则p1, p2交换后, 需要让next变更成为p1的后继节点
     *    
     *    2,3两点说的是: 把p1,p2当作一个整体的话,p1,p2交换位置后, 这个整体的前驱节点和后继节点都不应随意变动
     * @param list
     */
  public static void swapNeibor(MyLinkedList list){
      MyLinkedList.ListNode p1 = list.head;
      MyLinkedList.ListNode prev = null;
      while (p1 != null && p1.next != null){
          MyLinkedList.ListNode p2 = p1.next;
          p1.next = p2.next;
          p2.next = p1;
          if (prev != null){
              prev.next = p2;
          }else {// 头节点发生变更 很容易忘掉这个,链表是用头节点代表自己的
              list.head = p2;

          }
          prev = p1;
          p1 = p1.next;
      }

  }
}

测试程序

  public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        for(int i=1; i<=6; i++){
            list.addAtTail(i);
        }
        System.out.println(list);

        LinkedListUtils.swapNeibor(list);

        System.out.println(list);
    }

测试结果

1 -> 2 -> 3 -> 4 -> 5 -> 6
2 -> 1 -> 4 -> 3 -> 6 -> 5

反转链表

算法

 public static void reverseLinkList(MyLinkedList list) {
        MyLinkedList.ListNode p1 = list.head;
        MyLinkedList.ListNode prev = null; //prev及其之前的节点已经倒序了
        while (p1 != null) {
            list.head = p1;
            MyLinkedList.ListNode p2 = p1.next;//记住老的p1.next
            p1.next = prev;
            prev = p1;
            if (p2 != null) {
                list.head = p2;
                p1 = p2.next;
                p2.next = prev;
                prev = p2;
            } else break; //这一个break很重要,否则当p1 != null, p2 == null时,p1永远没有等于null的机会,会导致死循环
        }
    }

测试程序

 public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        for(int i=1; i<=6; i++){
            list.addAtTail(i);
        }
        System.out.println(list);

        LinkedListUtils.reverseLinkList(list);

        System.out.println(list);
    }

测试结果

1 -> 2 -> 3 -> 4 -> 5 -> 6
6 -> 5 -> 4 -> 3 -> 2 -> 1

猜你喜欢

转载自blog.csdn.net/dinghua_xuexi/article/details/107334608