Java - 单向无头不循环 - 链表增删查改实现、讲义链表OJ题实现

单向无头不循环链表实现

MyLinkedList.java文件

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

public class MyLinkedList {
    
    
    //首先需要定义一个链表的头结点  先用穷举法定义一个链表
    public ListNode head;
    public void createList() {
    
    
        ListNode listNode1 = new ListNode(12);
        ListNode listNode2 = new ListNode(23);
        ListNode listNode3 = new ListNode(34);
        ListNode listNode4 = new ListNode(45);
        ListNode listNode5 = new ListNode(56);
        this.head = listNode1;
        listNode1.next = listNode2;
        listNode2.next = listNode3;
        listNode3.next = listNode4;
        listNode4.next = listNode5;
    }
    //打印链表的val值
    public void display() {
    
    
        ListNode cur = this.head;
        while (cur != null) {
    
    
            System.out.print(cur.val+ " ");
            cur = cur.next;
        }
        System.out.println();
    }
    //从指定头节点开始打印
    public void display(ListNode newHead) {
    
    
        ListNode cur = newHead;
        while (cur != null) {
    
    
            System.out.print(cur.val+ " ");
            cur = cur.next;
        }
        System.out.println();
    }

    //实现链表的大小size()方法
    public int size() {
    
    
        int count = 0;
        ListNode cur = this.head;
        while (cur != null) {
    
    
            count++;
            cur = cur.next;
        }
        return count;
    }
    //判断是否包含关键字key在单链表中,返回boolean值
    public boolean contains(int key) {
    
    
        ListNode cur = this.head;
        while (cur != null) {
    
    
            if (cur.val == key) {
    
    
                return true;
            }
            cur = cur.next;
        }
        return false;
    }
    //实现头插法
    public void addList(int data) {
    
    
        ListNode node = new ListNode(data);
        node.next = this.head;
        head = node;
    }
    //实现尾插法
    public void addLast(int data) {
    
    
        ListNode node = new ListNode(data);
        //如果头结点为null,会有空指针异常,所以要判断头结点是否为null
        if (this.head == null) {
    
    
            this.head = node;
            return;
        }
        ListNode cur = this.head;
        while(cur.next != null) {
    
    
            cur = cur.next;
        }
        cur.next = node;
    }
    //实现clear函数
    public void clear() {
    
    
        //粗暴的方法:直接将head头结点置为null
//        this.head = null;
        //温柔的方法:单链表中一个一个的置为null
        while(this.head != null) {
    
    
            ListNode curNext = this.head.next;
            this.head.next = null;
            this.head = curNext;
        }
    }
    //删除第一次出现关键字为key的节点
    public void remove(int key) {
    
    
        if (this.head == null) {
    
    
            System.out.println("单链表为空,不能删除");
            return;
        }
        if (this.head.val == key) {
    
    
            this.head = this.head.next;
            return;
        }
        ListNode cur = searchPrev(key);
        if (cur == null) {
    
    
            System.out.println("没有你要删除的节点");
            return;
        }
        ListNode del = cur.next;
        cur.next = del.next;
    }
    //找出要删除的前一个节点,返回前一个节点
    public ListNode searchPrev(int key) {
    
    
        ListNode cur = this.head;
        while (cur != null) {
    
    
            if (cur.next.val == key) {
    
    
                return cur;
            }
            cur = cur.next;
        }
        return null;
    }
    //删除所有值为key的节点
    public void removeAllKey(int key) {
    
    
        if (this.head == null) {
    
    
            return ;
        }
        ListNode prev = this.head;
        ListNode cur = this.head.next;
        while (cur != null) {
    
    
            if (cur.val == key) {
    
    
                prev.next = cur.next;
                cur = cur.next;
            }else {
    
    
                prev = cur;
                cur = cur.next;
            }
        }
        if (this.head.val == key) {
    
    
            this.head = this.head.next;
        }
    }

    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data) {
    
    
        ListNode node = new ListNode(data);
        if (index < 0 ||index > size()) {
    
    
            System.out.println("index下标不合法");
            return;
        }
        if (index == 0) {
    
    
            addList(data);
            return;
        }
        if (index == size()) {
    
    
            addLast(data);
            return;
        }
        ListNode cur = findIndex(index);
        node.next = cur.next;
        cur.next = node;
    }
    public ListNode findIndex(int index) {
    
    
        ListNode cur = this.head;
        while (index-1 != 0) {
    
    
            cur = cur.next;
            index--;
        }
        return cur;
    }
    //反转一个单链表   老师写的方法
    public ListNode reverseList () {
    
    
        if (this.head == null) {
    
    
            return null;
        }
        ListNode cur = this.head;
        ListNode prev = null;
        ListNode curNext;
        while(cur != null) {
    
    
            curNext = cur.next;
            cur.next = prev;
            prev = cur;
            cur = curNext;
        }
        this.head = prev;
        return prev;
    }
    //反转一个单链表    我写出来的方法
    public ListNode reverseList2 () {
    
    
        if (this.head == null) {
    
    return null;}
        ListNode cur = this.head;
        ListNode curNext = cur.next;
        ListNode tmp;
        while (curNext != null) {
    
    
            tmp = curNext.next;
            curNext.next = cur;
            cur = curNext;
            curNext = tmp;
        }
        this.head.next = null;
        this.head = cur;
        return head;
    }
    //给定一个带有头结点head的非空单链表,返回链表的中间节点。如果有两个中间节点,则返回第二个中间节点。
    //使用快慢指针,路程不一样。当fast为slow的两倍速时,fast结束,slow就在中间路程。
    public  ListNode middleNode(ListNode head) {
    
    
        if (this.head == null) {
    
    
            return  null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
    
       //先判断fast是否为空,然后再判断fast.next是否为空
            fast = fast.next.next;                    //不然,如果fast为空,fast.next就会空指针异常
            slow = slow.next;
        }
        return slow;
    }

//    输入一个链表,输出该链表中倒数第k个节点
    public ListNode func4 (int k) {
    
    
//        if (k <= 0 || k > size()) {
    
    
        if (k <= 0 || head == null) {
    
    
            System.out.println("k值超过范围,不合法!");
            return null;
        }
        ListNode fast = this.head;
        ListNode slow = this.head;
        while (k-1 != 0) {
    
    
            fast = fast.next;
            if (fast == null) {
    
    
                System.out.println("k值超过范围,不合法!");
                return null;
            }
            k--;
        }
        while (fast.next != null) {
    
    
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }

    //在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针
    public ListNode func7() {
    
    
        //设置一个傀儡节点newHead,让tmp指向newHead,然后将重复的和不重复的分类
        ListNode newHead = new ListNode(-1);
        ListNode tmp = newHead;
        ListNode cur = this.head;
        while (cur != null) {
    
    
            //保证cur.next也不为null
            if (cur.next != null && cur.val == cur.next.val) {
    
    
                //while是单独的循环,需要重新控制限制条件
                while (cur.next != null && cur.val == cur.next.val) {
    
    
                    cur = cur.next;
                }
                cur = cur.next;
            }else {
    
    
                tmp.next = cur;
                tmp = tmp.next;
                cur = cur.next;
            }
        }
        //防止最后一个也是重复的,被删掉。所以,也要判断一下,手动置为null
        tmp.next = null;
        return newHead.next;
    }



}

TestDemo.java

public class TestDemo {
    
    
    //将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
    public static ListNode func5 (ListNode headA, ListNode headB) {
    
    
        ListNode newHead = new ListNode(-1);
        ListNode tmp = newHead;
        while(headA != null && headB !=null) {
    
    
            if (headA.val < headB.val) {
    
    
                tmp.next = headA;
                headA = headA.next;
                tmp = tmp.next;
            }else {
    
    
                tmp.next = headB;
                headB = headB.next;
                tmp = tmp.next;
            }
        }
        if (headA != null) {
    
    
            tmp.next = headA;
        }
        if (headB != null) {
    
    
            tmp.next = headB;
        }
        return newHead.next;
    }
    //编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前,最后返回新链表的头结点。
    public static ListNode func6(ListNode head,int x) {
    
    
        //设置四个引用对象,分别代表小于x的链表的前后节点,和大于等于x的链表的前后节点,然后再相连。
        ListNode bs = null;
        ListNode be = null;
        ListNode as = null;
        ListNode ae = null;
        ListNode cur = head;
        while (cur != null) {
    
    
            if (cur.val < x) {
    
    
                if (be == null) {
    
    
                    bs = cur;
                    be = cur;
                }else {
    
    
                    be.next = cur;
                    be = be.next;
                }
            }else {
    
    
                if (ae == null) {
    
    
                    ae = cur;
                    as = cur;
                }else {
    
    
                    ae.next = cur;
                    ae = ae.next;
                }
            }
            cur = cur.next;
        }
        //有可能没有小于x的值,如果没有小于x得值,be.next就会报空指针异常错误,所以要判断一下。(没有大于x的值的情况包括在里面了)
        if (be == null) {
    
    
            return as;
        }
        //防止最后一位节点的next不为null
        // (当最后一个节点小于x的时候,将其放在前面,后面如果有大于x的节点的值,最后一个节点的next不为null)
        // 就需要手动将最后一位置为null
        if(ae != null && ae.next != null) {
    
    
            ae.next = null;
        }
        be.next = as;
        return bs;
    }

    //第8道题 判断是不是回文
    public static boolean func8(ListNode head) {
    
    
        //第一步:找中间节点(定义一个快慢指针)
        if (head == null) {
    
    
            return true;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next !=null) {
    
    
            fast = fast.next.next;
            slow = slow.next;
        }
        //此时,中间节点为slow。第二步逆置
        ListNode cur = slow.next;
        ListNode curNext = cur.next;
        while (cur != null) {
    
    
            curNext = cur.next;
            cur.next = slow;
            slow = cur;
            cur = curNext;
        }
        //第三步:
        while (head != slow) {
    
    
            if (head.val != slow.val) {
    
    
                return false;
            }
            if (head.next == slow) {
    
    
                return true;
            }
            head = head.next;
            slow = slow.next;
        }
        return true; //相遇了就return true
    }

    //第9道题 输入两个链表,找出它们的第一个公共结点。
    public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    
    
        if(headA == null || headB == null) {
    
    
            return null;
        }

        ListNode pl = headA;
        ListNode ps = headB;
        int lenA = 0;
        int lenB = 0;
        while (pl != null) {
    
    
            lenA++;
            pl = pl.next;
        }
        //pl==null
        pl = headA;
        while (ps != null) {
    
    
            lenB++;
            ps = ps.next;
        }
        //ps==null
        ps = headB;
        int len = lenA-lenB;//差值步
        if(len < 0) {
    
    
            pl = headB;
            ps = headA;
            len = lenB-lenA;
        }
        //1、pl永远指向了最长的链表   ps 永远指向了最短的链表  2、求到了差值len步
        while (len != 0) {
    
    
            pl = pl.next;
            len--;
        }
        while (pl != ps ) {
    
    
            pl = pl.next;
            ps = ps.next;
        }
        return pl;
    }
    // pl走差值len步
    // 同时走 直到相遇


    //第十题:给定一个链表,判断链表中是否有环。
    public static boolean func10(ListNode head) {
    
    
        if (head == null) {
    
    
            return false;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
    
    
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
    
    
                return true;
            }
        }
        return false;
    }

    //第十一题:给定一个链表,返回链表开始入环的第一个节点。如果链表无环,则返回null
    public static ListNode func11(ListNode head) {
    
    
        if (head == null) {
    
    
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
    
    
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
    
    
                break;
            }
        }
        if (fast == null || fast.next == null) {
    
    
            return null;
        }
//        return  true;
        //方法走到这一行,说明单链表有环。
        ListNode cur = head;
        while (fast != cur) {
    
    
            fast = fast.next;
            cur = cur.next;
        }
        return fast;
    }

    //把没环的单链表编程有换的单链表
    public static void hasCircle(ListNode head) {
    
    
        ListNode cur = head;
        while(cur.next != null) {
    
    
            cur = cur.next;
        }
        cur.next = head.next.next;
    }
    //将两个链表变成Y相交的链表
    public static void intersection(ListNode headA,ListNode headB) {
    
    
        ListNode cur = headB;
        while (cur.next != null) {
    
    
            cur = cur.next;
        }
        cur.next = headA.next.next.next;
    }

    //用递归实现删除所有值为key的节点
    public static ListNode removeAllKey2(ListNode head,int key) {
    
    
        if(head == null){
    
    
            return null;
        }
        //递归调用
        ListNode res = removeAllKey2(head.next,key);
        if(head.val == key){
    
    
            return res;
        }else {
    
    
            head.next = res;
            return head;
        }
    }
    //用递归实现反转单链表
    public static ListNode reverseList2(ListNode head) {
    
    
        if (head == null ||head.next == null) {
    
    
            return head;
        }
        ListNode ret = reverseList2(head.next);
        head.next.next = head;
        head.next = null;
        return ret;
    }

    public static void main(String[] args) {
    
    
        MyLinkedList myLinkedList = new MyLinkedList();
        MyLinkedList myLinkedList1 = new MyLinkedList();
        myLinkedList1.addLast(11);
        myLinkedList1.addLast(27);

//        myLinkedList1.display();
//        myLinkedList.createList();
        myLinkedList.addLast(1);
        myLinkedList.addLast(2);
        myLinkedList.addLast(3);
        myLinkedList.addLast(4);
        myLinkedList.addLast(5);
        myLinkedList.display();
//        TestDemo.intersection(myLinkedList.head, myLinkedList1.head);
//        myLinkedList.head = TestDemo.removeAllKey2(myLinkedList.head,23);
//        myLinkedList.head = TestDemo.reverseList2(myLinkedList.head);
        myLinkedList.display(TestDemo.reverseList2(myLinkedList.head));
//        ListNode node = TestDemo.getIntersectionNode(myLinkedList.head, myLinkedList1.head);
//        System.out.println(node.val);
//        System.out.println(TestDemo.func10(myLinkedList.head));
//        TestDemo.hasCircle(myLinkedList.head);
//        System.out.println(TestDemo.func10(myLinkedList.head));
//        ListNode node = TestDemo.func11(myLinkedList.head);
//        System.out.println(node.val);
//        ListNode ret = TestDemo.func5(myLinkedList.head,myLinkedList1.head);
//        boolean flg = TestDemo.func8(myLinkedList.head);
//        System.out.println(flg);
//        ListNode ret = TestDemo.func6(myLinkedList.head,29);
//        System.out.println(myLinkedList.func4(2).val);
//        myLinkedList.func7();
//        myLinkedList.display(ret);
//        ListNode ret = myLinkedList.func4(7);
//        ListNode ret = myLinkedList.middleNode(myLinkedList.head);
//        System.out.println(ret.val);
//        ListNode ret = myLinkedList.reverseList();
//        ListNode ret1 = myLinkedList.reverseList2();
//        myLinkedList.display(ret1);
//        myLinkedList.remove(56);
//        myLinkedList.display();
//        myLinkedList.removeAllKey(23);
//        myLinkedList.display();
//        myLinkedList.clear();
//        myLinkedList.addIndex(1,400);
//        myLinkedList.display();
//        System.out.println(myLinkedList.size());
//        System.out.println(myLinkedList.contains(56));


    }
}

超链接:JAVA递归思想解决链表删除元素问题

单链表面试题

  1. 删除链表中等于给定值 val 的所有节点。 OJ链接
  2. 反转一个单链表。 OJ链接
  3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。OJ链接
  4. 输入一个链表,输出该链表中倒数第k个结点。 OJ链接
  5. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。OJ链接
  6. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。OJ链接
  7. 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 OJ链接
  8. 链表的回文结构。OJ链接
  9. 输入两个链表,找出它们的第一个公共结点。OJ链接
  10. 给定一个链表,判断链表中是否有环。 OJ链接
  11. 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null OJ链接
  12. 其他 。ps:链表的题当前因为难度及知识面等等原因还不适合我们当前学习,以后大家自己下去以后 Leetcode
    OJ链接
    + 牛客 OJ链接

猜你喜欢

转载自blog.csdn.net/qq_43398758/article/details/121246377