java----链表 (数据结构)

链表

1. 链表的功能

a> 头插法

 	//头插法
    public void addFirst(int data) {
        Node node = new Node(data);
//        if (this.head == null) {
//            this.head = node;
//        } else {
//            node.next = this.head;
//            this.head = node;
//        }
        node.next = this.head;
        this.head = node;
//        System.out.println("头插成功");
      }

b> 尾插法

	//尾插法
    public void addEnd(int data) {
        Node node = new Node(data);
        //判断链表是不是第一次插入
//        Node node1 = this.head;
//        if (node1 == null) {
//            node1 = node;
//            this.head = node1;
//            return;
//        }
        if (this.head == null) {
            this.head = node;
//            System.out.println("尾插成功");
            return;
        }
        //找最后一个节点
        Node cur = this.head;
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = node;
//        System.out.println("尾插成功");
    }

c> 任意插

 //任意位置插入, 第一个数据结点下标为 0
    public void addIndex(int index ,int data) {
        if (!checkIndex(index)) {
            return;
        }
        //方法一: 调用函数
        //第一个元素 : 头插
        if (index == 0) {
//            System.out.print("任意插,调用");
            addFirst(data);
            return;
        }
        //最后一个元素 : 尾插
        if (index == this.getLength()) {
//            System.out.print("任意插,调用");
            addEnd(data);
            return;
        }
        //中间元素 : 1.先找到插入点前一个元素结点. 2.再进行插入
        Node node = new Node(data);
        //保存前一个节点
        Node pre = searchPre(index);
        node.next = pre.next;
        pre.next = node;
//        System.out.println("任意插,插入成功");

        //方法二: 不调用函数直接写
//        Node node = new Node(data);
//        if (index == 0) {
//            node.next = this.head;
//            this.head = node;
//            System.out.println("插入成功");
//            return;
//        }
//        //找到插入点前一个元素
//        Node cur = this.head;
//        int count = 0;
//        while (count < index - 1 && cur.next != null) {
//            cur = cur.next;
//            count++;
//        }
//        //同时满足采用尾插法
//        if (count == index - 1 && cur.next == null) {
//            addEnd(data);
//            return;
//        }
//        if (count == index - 1) {
//            node.next = cur.next;
//            cur.next = node;
//        }
//        if (count < index - 1) {
//            System.out.println("插入位置有误");
//        }
//        System.out.println("任意插,插入成功");
    }

d> 查找关键字 key

 //查找是否包含关键字 key 的结点
    public boolean contains(int key) {
        if (this.head == null) {
//            System.out.println("不存在该关键字 key = " + key);
            return false;
        }
        // 查找关键字为 key 的结点的前驱节点
        // 1. 前驱节点为 null :①头结点的前驱结点为 null ②关键字 key 不存在的结点前驱结点为 null
        // 比较头结点的 data值 是否等于 key;
        // 相等返回 true; 否则 false;
        // 2. 前驱节点不为 null : 包含关键字为 key 的结点: 返回 true;
        if (searchPreNode(key) == null) {
            if (this.head.data == key) {
                return true;
            } else {
//                System.out.println("不存在该关键字 key = " + key);
                return false;
            }
        }
        return true;
    }

e> 删除第一次出现关键字 key 的结点

    //删除第一次出现关键字 key 的结点
    public void remove(int key) {
        if (this.head == null) {
            return;
        }
        // 方法一: 使用 contains 函数

        if (!contains(key)) {
            return;
        }else if (this.head.data == key) {
            this.head = this.head.next;
//            System.out.println("删除成功");
        }else {
            searchPreNode(key).next = searchPreNode(key).next.next;
//            System.out.println("删除成功");
        }
        //方法二: 直接写

        //前驱节点为 null :
        // 1. 头结点的前驱结点为 null
        // 2. 关键字 key 不存在的结点前驱结点为 null
//        if (searchPreNode(key) == null) {
//            //删除头结点
//            if (this.head.data == key) {
//                this.head = this.head.next;
//                 System.out.println("删除成功");
//            } else {
//                System.out.println("不存在该关键字 key = " + key);
//            }
//            return;
//        }
//        //前驱节点不为 null
//        Node pre = searchPreNode(key);
//        pre.next = pre.next.next;
//        System.out.println("删除成功");
    }

f> 删除所有值为 key 的结点

    //删除所有值为 key 的结点
    public void removeAllKey(int key) {
        if (this.head == null) {
            return;
        }
//        //方法一: 只遍历一次单链表把所有值为 key 的结点删除
//        //删除头结点
//        while (this.head.data == key) {
//            this.head = this.head.next;
//        }
//        //删除普通结点
//        Node cur = this.head;
//        while (cur.next != null) {
//            while (cur.next.data == key) {
//                cur.next = cur.next.next;
//            }
//            cur = cur.next;
//        }
        //方法二: 只遍历一次单链表把所有值为 key 的结点删除
        Node pre = this.head;
        Node cur1 = this.head.next;
        while (cur1 != null) {
            if (cur1.data == key) {
                pre.next = pre.next.next;
                cur1 = pre.next;
            }else {
                pre = cur1;
                cur1 = cur1.next;
            }
        }
        if (this.head.data == key) {
            this.head = this.head.next;
        }
        //方法三: 调用函数
//        while (contains(key)) {
//            if (searchPreNode(key) == null) {
//                //删除头结点
//                this.head = this.head.next;
//                return;
//            }else {
//                Node pre = searchPreNode(key);
//                pre.next = pre.next.next;
//            }
//        }
    }

g> 反转

    //反转:  采用头插法
    public Node reverseList() {
        if (this.head == null) {
            return null;
        }
        //采用头插法
        Node node1 = this.head.next;
        Node node2 = this.head;
        while (node1 != null) {
            addFirst(node1.data);
            node1 = node1.next;
        }
        node2.next = null;
        return head;
    }

h> 返回中间结点

    //返回中间结点: 只遍历一次单链表
    public Node middleList() {
        // slow 一次走一步
        Node slow = this.head;
        // fast 一次走两步
        Node fast = this.head;
        // 第一个条件是针对头指针为空指针,也就是说链表为空
        // 条件顺序不能交换: 否则会出现空指针异常
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

i> 输出该链表中倒数第 K 个结点

   //输入一个链表,输出该链表中倒数第 K 个结点
    // 只遍历单链表一次: 即不能求长度
    public Node findKthRe(int k) {
        if (k <= 0) {
            return null;
        }
        //方法一:
        Node slow = this.head;
        Node fast = this.head;
        int fastCount = 0;
        while (fast != null && fast.next != null && fastCount < k - 1) {
            fast = fast.next;
            fastCount++;
        }
        // k 超越单链表长度
        if (fastCount < k - 1) {
            return null;
        }
        while (fast.next != null) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
        //方法二:
//        this.reverseList();
//        return searchPre(k);
        //方法三:
//        return searchPre(this.getLength() - k + 1);
    }

j> 写一个代码,将小于 x 的元素放在 x 左边,大于等于 x 的放在右边

    //编写一个代码,将小于 x 的元素放在 x 左边,大于等于 x 的放在右边
    public Node partition(int x) {
        Node bs = null;
        Node be = null;
        Node as = null;
        Node ae = null;
        Node cur = this.head;
        while (cur != null) {
            if (cur.data < x) {
                //尾插
                if (bs == null) {
                    //第一次插入
                    bs = cur;
                    be = cur;
                }else {
                    be.next = cur;
                    be = be.next;
                }
            }else {
                //尾插
                if (as == null) {
                    // 第一次插入
                    as = cur;
                    ae = cur;
                }else {
                    ae.next = cur;
                    ae = ae.next;
                }
            }
            cur = cur.next;
        }
        if (bs == null) {
            this.head = as;
        }else if (as == null) {
            be.next = null;
            this.head = bs;
        }else {
            be.next = as;
            ae.next = null;
            this.head = bs;
        }
        return this.head;
    }

k> 检查 index 位置是否为插入有效位置

    //检查 index 位置是否为插入有效位置
    public boolean checkIndex(int index) {
        if (index < 0 || index > this.getLength()) {
            System.out.println("该单链表目前长度为 : " + this.getLength() + ", 插入位置 index = " + index + "有误!");
            return false;
        }
        return true;
    }

l> 找关键字 key 对应节点的前驱结点

    //找关键字 key 对应节点的前驱结点
    public Node searchPreNode(int key) {
        Node cur = this.head;
        while (cur.next != null) {
            if (cur.next.data == key) {
                return cur;
            }
            cur = cur.next;
        }
        return null;
    }

m> 找 index 结点的前驱结点

    //找 index 结点的前驱结点
    public Node searchPre(int index) {
        Node cur = this.head;
        for (int i = 0; i < index - 1; i++) {
            cur = cur.next;
        }
        return cur;

    }

n> 计算单链表长度

    //计算单链表长度
    public int getLength() {
        if (this.head == null) {
            return 0;
        }
        int count = 0;
        Node node1 = this.head;
        while (node1 != null) {
            node1 = node1.next;
            count++;
        }
        return count;
    }

o> 清空单链表

    //清空单链表
    public void clear() {
        this.head = null;
        //内存泄漏
    }

p> 打印

    //打印
    public void display() {
        Node cur = this.head;
        while (cur != null) {
            System.out.print(cur.data + " ");
            cur = cur.next;
        }
        System.out.println();
    }

2. 源代码

/**
 * @author FMM
 * @version 7.0
 * @date 2021/1/14 10:06
 */
public class MyLinkedList {
    //表示链表头结点
    public Node head;

    //头插法
    public void addFirst(int data) {
        Node node = new Node(data);
//        if (this.head == null) {
//            this.head = node;
//        } else {
//            node.next = this.head;
//            this.head = node;
//        }
        node.next = this.head;
        this.head = node;
//        System.out.println("头插成功");
      }

      //尾插法
    public void addEnd(int data) {
        Node node = new Node(data);
        //判断链表是不是第一次插入
//        Node node1 = this.head;
//        if (node1 == null) {
//            node1 = node;
//            this.head = node1;
//            return;
//        }
        if (this.head == null) {
            this.head = node;
//            System.out.println("尾插成功");
            return;
        }
        //找最后一个节点
        Node cur = this.head;
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = node;
//        System.out.println("尾插成功");
    }

    //任意位置插入, 第一个数据结点下标为 0
    public void addIndex(int index ,int data) {
        if (!checkIndex(index)) {
            return;
        }
        //方法一: 调用函数
        //第一个元素 : 头插
        if (index == 0) {
//            System.out.print("任意插,调用");
            addFirst(data);
            return;
        }
        //最后一个元素 : 尾插
        if (index == this.getLength()) {
//            System.out.print("任意插,调用");
            addEnd(data);
            return;
        }
        //中间元素 : 1.先找到插入点前一个元素结点. 2.再进行插入
        Node node = new Node(data);
        //保存前一个节点
        Node pre = searchPre(index);
        node.next = pre.next;
        pre.next = node;
//        System.out.println("任意插,插入成功");

        //方法二: 不调用函数直接写
//        Node node = new Node(data);
//        if (index == 0) {
//            node.next = this.head;
//            this.head = node;
//            System.out.println("插入成功");
//            return;
//        }
//        //找到插入点前一个元素
//        Node cur = this.head;
//        int count = 0;
//        while (count < index - 1 && cur.next != null) {
//            cur = cur.next;
//            count++;
//        }
//        //同时满足采用尾插法
//        if (count == index - 1 && cur.next == null) {
//            addEnd(data);
//            return;
//        }
//        if (count == index - 1) {
//            node.next = cur.next;
//            cur.next = node;
//        }
//        if (count < index - 1) {
//            System.out.println("插入位置有误");
//        }
//        System.out.println("任意插,插入成功");
    }

    //查找是否包含关键字 key 的结点
    public boolean contains(int key) {
        if (this.head == null) {
//            System.out.println("不存在该关键字 key = " + key);
            return false;
        }
        // 查找关键字为 key 的结点的前驱节点
        // 1. 前驱节点为 null :①头结点的前驱结点为 null ②关键字 key 不存在的结点前驱结点为 null
        // 比较头结点的 data值 是否等于 key;
        // 相等返回 true; 否则 false;
        // 2. 前驱节点不为 null : 包含关键字为 key 的结点: 返回 true;
        if (searchPreNode(key) == null) {
            if (this.head.data == key) {
                return true;
            } else {
//                System.out.println("不存在该关键字 key = " + key);
                return false;
            }
        }
        return true;
    }

    //删除第一次出现关键字 key 的结点
    public void remove(int key) {
        if (this.head == null) {
            return;
        }
        // 方法一: 使用 contains 函数

        if (!contains(key)) {
            return;
        }else if (this.head.data == key) {
            this.head = this.head.next;
//            System.out.println("删除成功");
        }else {
            searchPreNode(key).next = searchPreNode(key).next.next;
//            System.out.println("删除成功");
        }
        //方法二: 直接写

        //前驱节点为 null :
        // 1. 头结点的前驱结点为 null
        // 2. 关键字 key 不存在的结点前驱结点为 null
//        if (searchPreNode(key) == null) {
//            //删除头结点
//            if (this.head.data == key) {
//                this.head = this.head.next;
//                 System.out.println("删除成功");
//            } else {
//                System.out.println("不存在该关键字 key = " + key);
//            }
//            return;
//        }
//        //前驱节点不为 null
//        Node pre = searchPreNode(key);
//        pre.next = pre.next.next;
//        System.out.println("删除成功");
    }

    //删除所有值为 key 的结点
    public void removeAllKey(int key) {
        if (this.head == null) {
            return;
        }
//        //方法一: 只遍历一次单链表把所有值为 key 的结点删除
//        //删除头结点
//        while (this.head.data == key) {
//            this.head = this.head.next;
//        }
//        //删除普通结点
//        Node cur = this.head;
//        while (cur.next != null) {
//            while (cur.next.data == key) {
//                cur.next = cur.next.next;
//            }
//            cur = cur.next;
//        }
        //方法二: 只遍历一次单链表把所有值为 key 的结点删除
        Node pre = this.head;
        Node cur1 = this.head.next;
        while (cur1 != null) {
            if (cur1.data == key) {
                pre.next = pre.next.next;
                cur1 = pre.next;
            }else {
                pre = cur1;
                cur1 = cur1.next;
            }
        }
        if (this.head.data == key) {
            this.head = this.head.next;
        }
        //方法三: 调用函数
//        while (contains(key)) {
//            if (searchPreNode(key) == null) {
//                //删除头结点
//                this.head = this.head.next;
//                return;
//            }else {
//                Node pre = searchPreNode(key);
//                pre.next = pre.next.next;
//            }
//        }
    }

    //反转:  采用头插法
    public Node reverseList() {
        if (this.head == null) {
            return null;
        }
        //采用头插法
        Node node1 = this.head.next;
        Node node2 = this.head;
        while (node1 != null) {
            addFirst(node1.data);
            node1 = node1.next;
        }
        node2.next = null;
        return head;
    }

    //返回中间结点: 只遍历一次单链表
    public Node middleList() {
        // slow 一次走一步
        Node slow = this.head;
        // fast 一次走两步
        Node fast = this.head;
        // 第一个条件是针对头指针为空指针,也就是说链表为空
        // 条件顺序不能交换: 否则会出现空指针异常
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

    //输入一个链表,输出该链表中倒数第 K 个结点
    // 只遍历单链表一次: 即不能求长度
    public Node findKthRe(int k) {
        if (k <= 0) {
            return null;
        }
        //方法一:
        Node slow = this.head;
        Node fast = this.head;
        int fastCount = 0;
        while (fast != null && fast.next != null && fastCount < k - 1) {
            fast = fast.next;
            fastCount++;
        }
        // k 超越单链表长度
        if (fastCount < k - 1) {
            return null;
        }
        while (fast.next != null) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
        //方法二:
//        this.reverseList();
//        return searchPre(k);
        //方法三:
//        return searchPre(this.getLength() - k + 1);
    }

    //编写一个代码,将小于 x 的元素放在 x 左边,大于等于 x 的放在右边
    public Node partition(int x) {
        Node bs = null;
        Node be = null;
        Node as = null;
        Node ae = null;
        Node cur = this.head;
        while (cur != null) {
            if (cur.data < x) {
                //尾插
                if (bs == null) {
                    //第一次插入
                    bs = cur;
                    be = cur;
                }else {
                    be.next = cur;
                    be = be.next;
                }
            }else {
                //尾插
                if (as == null) {
                    // 第一次插入
                    as = cur;
                    ae = cur;
                }else {
                    ae.next = cur;
                    ae = ae.next;
                }
            }
            cur = cur.next;
        }
        if (bs == null) {
            this.head = as;
        }else if (as == null) {
            be.next = null;
            this.head = bs;
        }else {
            be.next = as;
            ae.next = null;
            this.head = bs;
        }
        return this.head;
    }

    //遍历单链表一次,删除相同的结点
    // eg: 1 2 2 12 12 17------> 1 17

    //合并两个有序列表
    public Node Merge(Node node1, Node node2) {

        while (node1 != null && node2 != null) {

            while (node1 != null) {
                node1 = node1.next;
            }
            while (node2 != null) {
                node2 = node2.next;
            }
        }
        return this.head;
    }

    //检查 index 位置是否为插入有效位置
    public boolean checkIndex(int index) {
        if (index < 0 || index > this.getLength()) {
            System.out.println("该单链表目前长度为 : " + this.getLength() + ", 插入位置 index = " + index + "有误!");
            return false;
        }
        return true;
    }

    //找关键字 key 对应节点的前驱结点
    public Node searchPreNode(int key) {
        Node cur = this.head;
        while (cur.next != null) {
            if (cur.next.data == key) {
                return cur;
            }
            cur = cur.next;
        }
        return null;
    }

    //找 index 结点的前驱结点
    public Node searchPre(int index) {
        Node cur = this.head;
        for (int i = 0; i < index - 1; i++) {
            cur = cur.next;
        }
        return cur;

    }

    //计算单链表长度
    public int getLength() {
        if (this.head == null) {
            return 0;
        }
        int count = 0;
        Node node1 = this.head;
        while (node1 != null) {
            node1 = node1.next;
            count++;
        }
        return count;
    }

    //清空单链表
    public void clear() {
        this.head = null;
        //内存泄漏
    }

    //打印
    public void display() {
        Node cur = this.head;
        while (cur != null) {
            System.out.print(cur.data + " ");
            cur = cur.next;
        }
        System.out.println();
    }
}

3. 测试类

/**
 * @author FMM
 * @version 7.0
 * @date 2021/1/14 10:14
 */
public class Main {
    public static void main(String[] args) {

        MyLinkedList myLinkedList = new MyLinkedList();
//        myLinkedList.addEnd(1000);
        myLinkedList.addIndex(0,100);
        myLinkedList.addFirst(2);
        myLinkedList.addFirst(3);
        myLinkedList.addFirst(5);
        myLinkedList.addFirst(1);
        myLinkedList.addFirst(10);
        myLinkedList.partition(3);
        myLinkedList.display();
//        myLinkedList.addEnd(5);
//        myLinkedList.addEnd(6);
//        //-1, 6 是非法插入
//        myLinkedList.addIndex(-1,10);
//        myLinkedList.addIndex(6,14);
//        //头插
//        myLinkedList.addIndex(0,11);
//        //尾插
//        myLinkedList.addIndex(6,12);
//        //中间插
//        myLinkedList.addIndex(5,13);
//        myLinkedList.remove(0);
//        //删除头结点
//        myLinkedList.remove(11);
//        //删除中间节点
//        myLinkedList.remove(2);
//        //删除尾结点
//        myLinkedList.remove(12);
//        //打印
//        myLinkedList.addIndex(4,5);
//        myLinkedList.display();
//        System.out.println(myLinkedList.contains(11));
//        System.out.println(myLinkedList.contains(100));
//        System.out.println(myLinkedList.contains(100));
//        myLinkedList.removeAllKey(5);
//        myLinkedList.addIndex(0,3);
//        myLinkedList.removeAllKey(3);
//        myLinkedList.display();
//        myLinkedList.reverseList();
//        myLinkedList.display();
        myLinkedList.remove(100);
//        System.out.println(myLinkedList.middleList());
//        myLinkedList.clear();
//        System.out.println(myLinkedList.findKthRe(2));
//        myLinkedList.display();
//        System.out.println("的点点滴滴错");
    }
}

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值