2021/9/14 ~15(单链表 + 单链表反转)

2021/9/14 ~15(单链表)

dizzy day

单链表习题

对于单链表的再度学习,我明白了引用的概念,变量在栈区,new 出来的对象在堆区。

变量可以操作内存中的数据。a = head. 指变量a指向head变量所在的内存区。 即a和head都指向了一块内存区。a和head = 其他值并不会改变内存地址的值。

做题了。

单链表反转4种方式

http://c.biancheng.net/view/8105.html

我这里的头节点包含了信息,在某些操作时还是需要头节点指针的(纯粹)

package LinkedList;

import java.util.Stack;

/**
 * 我定义的单向链表,其中第一个元素index为1
 *
 * @param <T>
 */
public class MyLinkedList<T> {
    private Node<T> head;
    private Node<T> tail;
    private int size; //仅仅记录链表长度,不做规定

    public Node<T> getTail() {
        return tail;
    }

    private class Node<T> {
        private T data;
        private Node<T> next;
        public Node() {
            data = null;
            next = null;
        }
        public Node(T data) {
            this.data = data;
            next = null;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "data=" + data +
                    ", next="  +
                    '}';
        }
    }

    public int getSize() {
        return this.size;
    }

    public void setTail(Node<T> tail) {
        this.tail = tail;
    }

    //构造函数
    public MyLinkedList() {
        this.head = null;
        this.tail = null;
        this.size = 0;
    }

    public T getFirst() throws Exception {
        rangeCheck();
        return this.head.data;
    }
    public Node<T> getHead(){
        return this.head;
    }
    private void rangeCheck() throws Exception {
        if (isEmpty()) {
            throw new Exception("List is empty");
        }
    }

    private void indexCheck(int index) throws Exception {
        if (index > this.size || index <= 0) {
            throw new IllegalArgumentException("Illegal Index");
        }
    }

    public T getLast() throws Exception {
        rangeCheck();
        return this.tail.data;
    }

    public Boolean isEmpty() {
        return this.size == 0;
    }

    public Boolean isNotEmpty() {
        return !isEmpty();
    }

    /**
     * 我定义第一个节点就为头节点,最后一个节点为size大小,index 从一开始
     */
    public T getAt(int index) throws Exception {
        return (T) getNodeAt(index).data;
    }

    /**
     * 根据Node中的data查找在表中的位序
     *
     * @param data
     */
    public int getIndexAt(T data) throws Exception {
        int index = 1;
        rangeCheck();
        Node<T> tmp = this.head;
        while (tmp != null && tmp.data != data) {
            tmp = tmp.next;
            index++;
        }
        if (tmp == null) return -1;
        else return index;
    }

    public Node getNodeAt(int index) throws Exception {
        rangeCheck();
        indexCheck(index);
        Node<T> temp = this.head;
        for (int i = 1; i <= index - 1; i++) {
            temp = temp.next; // 这段代码多多理解。temp = 一个内存地址
        }
        return temp;
    }

    /**
     * 尾插法
     *
     * @param data
     */
    public void addLast(T data) {
        // create
        Node<T> node = new Node();
        node.data = data;
        // attach
        if (isNotEmpty()) {
            this.tail.next = node;
        }
        if (isEmpty()) {
            this.head = node;
        }
        this.tail = node;
        this.size += 1;
    }

    /**
     * 头插法
     *
     * @param data
     */
    public void addFirst(T data) {
        Node<T> node = new Node();
        node.data = data;
        if (isNotEmpty()) {
            node.next = head;
        }
        if (isEmpty()) {
            this.tail = node;
        }
        this.head = node;
        this.size += 1;
    }
    public void addFirst(Node<T> node) {
        if (isNotEmpty()) {
            node.next = this.head;
        }
        if (isEmpty()) {
            this.tail = node;
            this.tail.next = null;
        }
        this.head = node;
        this.size += 1;
    }



    /**
     * 假如idx=1,那么头插,如果idx>siz,尾插
     *
     * @param data
     * @param idx
     */
    public void addAt(T data, int idx) throws Exception {
        if (idx <= 0) {
            throw new IllegalArgumentException("Illegal Index");
        }
        if (idx == 1) {
            addFirst(data);
        } else if (idx > size) {
            addLast(data);
        }
        Node<T> node = new Node();
        node.data = data;
        Node preNode = getNodeAt(idx - 1);
        node.next = preNode.next;
        preNode.next = node;
    }

    public T removeFirst() throws Exception {
        rangeCheck();
        Node<T> tmp = this.head;
        if (this.size == 1) {
            this.head = null;
            this.tail = null;
            this.size = 0;
        } else {
            head = head.next;
            this.size--;
        }
        return tmp.data;
    }

    public T removeLast() throws Exception {
        rangeCheck();
        if (this.size == 1) {
            this.head = null;
            this.tail = null;
            this.size = 0;
        }
        Node<T> tmp = this.tail;
        Node preNode = getNodeAt(this.size - 1);
        preNode.next = null;
        this.tail = preNode;
        this.size--;
        return tmp.data;
    }

    public T removeAt(int idx) throws Exception {
        rangeCheck();
        indexCheck(idx);
        if (idx == 1) {
            return removeFirst();
        } else if (idx == this.size) {
            return removeLast();
        }
        Node<T> prefix = getNodeAt(idx - 1);
        Node<T> removeNode = prefix.next;
        prefix.next = removeNode.next;
        this.size--;
        return removeNode.data;
    }

    public void removeAll() throws Exception {
        while (this.size > 0) {
            removeFirst();
        }
    }

    public void display() {
        System.out.println("========================");
        Node<T> temp = this.head;
        while (temp != null) {
            System.out.println(temp.data);
            temp = temp.next;
        }
        System.out.println("Over");
    }

    /**
     * 新的需求,根据id排序
     * 今天状态好差我就不写了
     * 思路:1。在头节点设置前缀:preHead
     * 2。有bug tail怎么变化呢?
     */
    public void addByOrder(Integer data) {
        Node<Integer> node = new Node<Integer>(data);
        Node<Integer> preHead = new Node<Integer>();
        preHead.next = (Node<Integer>) this.head;
        Node<Integer> tmp = preHead;
        while (true) {
            if (tmp.next == null) {
                addLast((T) data); // 操作有设置tail
                break;
            }
            if (tmp.next.data > node.data) {
                node.next = tmp.next;
                tmp.next = node;
                break;
            }
            if (tmp.next.data == node.data) {
                System.out.println("重复啦");
                break;
            }
            tmp = tmp.next;
        }

    }

    /**
     * 习题练习一 : 获取链表节点个数
     */
    public int getLength() {
        Node<T> tmp = this.head;
        int count = 0;
        while (tmp != null) {
            count++;
            tmp = tmp.next;
        }
        return count;
        // return getSize();
    }

    /**
     * 习题练习二:查找单链表中的倒数第index个节点、
     * 解答:因为是单链表,只能从头开始,不能从尾巴开始,效率有点低
     *
     * @param index
     * @return
     * @throws Exception
     */
    public Node<T> getIndexOfLast(int index) throws Exception {
        return getNodeAt(size - index + 1);
    }

    /**
     * 链表反转 解决方法一:头插法 2🌟🌟
     */
    public MyLinkedList<T> linkedListReverse() throws Exception {
        if (this.head==null || this.head.next==null){
            System.out.println("链表为空or只有一个节点");
            return null ;
        }
        MyLinkedList list = new MyLinkedList();
        Node<T> tmp;
        while(head!=null){
            tmp = this.head;
            head = head.next;
            list.addFirst(tmp);
        }
        return list;
    }

    /**
     * 链表反转 解决方法二:迭代反转   推荐指数🌟🌟🌟🌟🌟
     *          注意点:下面这种while循环不会导致空指针!
     */
    public void linkedListReverse2() {
        if (head == null || head.next == null) {
            System.out.println("can't not reverse");
            return;
        }
        Node<T> beg = null;
        Node<T> mid = head;
        Node<T> end = head.next;
        while (true) {
            mid.next = beg;
            if (end == null) {
                break;
            }
            beg = mid;
            mid = end;
            end = end.next;
        }
        Node<T> tmp = tail;
        tail = head;
        head = tmp;
    }
    /**
     * 链表反转 解决方法三:迭代反转    思路NB
     *                   推荐指数🌟🌟🌟🌟🌟
     *                   迭代可以反着来
     *                   不知道为什么有bug ==>需要解决首位的位置
     */
    public Node<T> linkedListReverse3(Node<T> head) throws Exception {
        if (head==null || head.next==null){
            // 需要交换首位的位置!!
            Node<T> tmp = this.head;
            this.head = head;
            this.tail = tmp;
            return head;
        }
        // newNode永远是尾
        Node<T> newNode = linkedListReverse3(head.next);
        head.next.next = head;
        head.next = null;
        return newNode;
    }

    /**
     * 逆序打印单链表  方式一:栈
     */
    public  void reverseListAndPrint(){
        if (head==null){
            return;
        }
        Stack<Node<T>> stack = new Stack<>();
        Node<T> copyHead = head;
        Node<T> tmp ;
        while(head!=null){
            tmp = head;
            head = head.next;
            stack.add(tmp);
        }
        this.head = copyHead;
        while(stack.size()>0){
            System.out.println(stack.pop());
        }
    }
    /**
     * 逆序打印单链表  方式二:递归
     *
     */
    public void reverseListAndPrint3(Node<T> head){
        if(head !=null && head.next!=null){
            reverseListAndPrint3(head.next);
        }
        System.out.println(head.data);
    }

}

测试

package LinkedList;

import LinkedList.pojo.Person;

import java.util.ArrayList;

public class MyLinkedListTest {
    public static void main(String[] args) throws Exception {
        MyLinkedList<Person> list = new MyLinkedList<Person>();
        Person person = new Person(1,"22",1);
        Person person2 = new Person(2,"22",1);
        Person person3 = new Person(3,"22",1);
        Person person4 = new Person(4,"22",1);
        list.addLast(person);
        list.addLast(person2);
        list.addLast(person4);
        list.addLast(person3);
        list.display();
        System.out.println("==");
        list.reverseListAndPrint3(list.getHead());
        System.out.println("size"+list.getSize());
        System.out.println("firse"+list.getFirst());
        System.out.println("last"+list.getLast());

        System.out.println("000000000000000000000000000000");
        // first element i.e.10 should be printed


        // element at 3rd index i.e.40 should be printed

        //System.out.println(list.getAt(3));

        // a memory address of a node should be printed

        System.out.println(list.getNodeAt(3));

        // 10 should be removed and printed

        System.out.println(list.removeFirst());

        // 40 should be removed and printed

        System.out.println(list.removeLast());

        // list without 10 and 40 should be printed

        list.display();

        // 100 should be added at first


        list.display();

        // 30 should be removed

        list.removeAt(2);

        // 300 should be added at 2nd index

        list.display();
        System.out.println(list.getSize());
        list.removeAll();
        System.out.println(list.getSize());

    }
}

posted @ 2021-09-16 18:36  能借我十块钱吗  阅读(39)  评论(0编辑  收藏  举报