2021.2.1随笔

2021.2.1 随笔

随笔高大上的名字,其实就是日记

单链表的操作

手写一个实现基本增删查改功能操作的单链表

public class MyLinked1 {
    Node top;
    int size;

    // 添加
    public boolean add(String str) {
        // 判断链表是否为空
        if (top == null || size == 0) {
            // 代表是一个空链表
            top = new Node(str, null);
            size++;
            return true;
        }

        // 查找尾结点
        Node mid = top;
        while (mid.next != null) {
            mid = mid.next;
        }
        // 上述循环的跳出条件,就是 mid 是尾结点
        mid.next = new Node(str, null);
        size++;
        return true;
    }

    // 删除
    public String delete(String str) {
        // TODO:参数校验:
        if (top == null || size == 0) {
            throw new RuntimeException("linked id null");
        }

        if (top.value.equals(str)) {
            // 要删除的结点是头结点
            top = top.next;
            size--;
            return str;
        }
        // 删除的不是头结点
        Node mid = top;

        // 向后查找要删除的结点
        // 如果查找的结点不指向 null 和该结点下一个结点的值不是 str ,就向后查找
        while (mid.next != null && !mid.next.value.equals(str)) {
            mid = mid.next;
        }

        // 意味着
        //      1.mid.next=null     没有删除的元素
        //      2.mid.next 就是要删除的结点
        if (mid.next == null) {
            // 没找到
            return null;
        }
        // mid.next 要找到结点
        mid.next = mid.next.next;
        size--;
        return str;
    }

    // 修改
    public boolean set(String oldStr, String newStr) {
        // TODO:参数校验:
        if (top == null || size == 0) {
            throw new RuntimeException("linked id null");
        }

        // 修改的是否是头结点
        if (top.value.equals(oldStr)) {
            top.value = newStr;
            return true;
        }

        // 修改的不是头结点
        Node mid = top;
        // 这个循环就是查找要替换的元素
        while (mid.next != null && !mid.next.value.equals(oldStr)) {
            mid = mid.next;
        }
        // 没找到
        if (mid.next == null) {
            return false;
        }
        // 必然找到
        mid.next.value = newStr;
        return true;


    }


    // 查找
    public boolean find(String str) {
        // TODO:参数校验
        if (top == null || size == 0) {
            throw new RuntimeException("linked is null");
        }
        // 查找的是不是头结点
        if (top.value.equals(str)) {
            return true;
        }
        // 不是头结点,就向后遍历
        Node mid = top;
        // 如果下一个不是null,并且下一个的值不是str
        while (mid.next != null && !mid.next.value.equals(str)) {
            mid = mid.next;
        }
        // 没找到
        if (mid.next == null) {
            return false;
        }
        // 必然找到
        return true;

    }

    // 根据下标删除
    public String idDelete(int id) {
        // TODO:参数校验
        if (top == null || size == 0) {
            throw new RuntimeException("linked is null");
        }
        if (id < 0 || id >= size) {
            throw new IllegalArgumentException("超出范围!");
        }
        // 判断是否是头结点
        if (id == 0) {
            String oldValue = top.value;
            top = top.next;
            size--;
            return oldValue;
        }
        Node mid = top;
        // 不是头结点,就向后遍历,查找被删除结点的前一个结点
        int i = 0;
        // 下面或许可以换成(id!=i)实现应该是一样的。
        while (mid.next != null && i < id - 1) {
            // 循环条件为小于 下标为 id-1 的 结点,
            mid = mid.next;
            i++;
        }
        if (mid.next == null) {
            // 写上保险,想法更全面。
        }
        // 被删除结点前一个结点的指针指向下下个结点。
        String oldStr = mid.next.value;
        mid.next = mid.next.next;
        size--;
        return oldStr;


    }

    // 选做:根据下标添加
    public boolean idAdd(String str, int id) {

        // 超出范围
        // 这里不能等于 size ,因为可以在尾结点添加啊
        if (id < 0 || id > size) {
            throw new IndexOutOfBoundsException("超出范围!");
        }
        // 判断空表,这段可能不太需要。
        if (top == null || size == 0) {
            top = new Node(str, null);
            size++;
            return true;
        }
        // 判断头结点
        if (id == 0) {
            Node newNode = new Node(str, top);
            top = newNode;
            size++;
            return true;
        }
        Node mid = top;
        int i = 1;  
        // 这里为什么要从1开始?,1--id  或者 0开始--(id-1)
        // 遍历找被添加结点的前一个结点。
        while (i < id ) {  // 等价于 i!=id
            mid = mid.next;
            i++;
        }
        // 必然添加
        Node newNode = new Node(str, mid.next);
        mid.next = newNode;
        size++;
        return true;

    }


    class Node {
        String value;
        Node next;

        public Node(String value, Node next) {
            this.value = value;
            this.next = next;
        }

        @Override
        public String toString() {
            return "{" +
                    "value=" + value +
                    "}" + next;
        }
    }

    @Override
    public String toString() {
        return "" + top;
    }
}

class Demo {
    public static void main(String[] args) {
        MyLinked1 myLinked1 = new MyLinked1();
        myLinked1.add("zs");
        myLinked1.add("ls");
        myLinked1.add("ww");
        myLinked1.add("zz");
        myLinked1.add("ss");
        myLinked1.add("mm");

//        System.out.println(myLinked1);
//        myLinked1.delete("ww");
//        myLinked1.set("ls", "ohou");

//        System.out.println(myLinked1.find("ssss"));  // 查找

//        myLinked1.idDelete(0);  // 头
//        System.out.println(myLinked1);
//        myLinked1.idDelete(3);  // 中间
//        System.out.println(myLinked1);
//        myLinked1.idDelete(5);  // 尾
//        System.out.println(myLinked1);
//


//        myLinked1.idAdd("萌萌",0);  // 头
//        System.out.println(myLinked1);
//        myLinked1.idAdd("萌萌",3);  // 中间
//        System.out.println(myLinked1);
        myLinked1.idAdd("萌萌", 6);  // 最后
        System.out.println(myLinked1);


    }
}

总结:最初开始接触链表也有点懵,纯按自己的理解写了一个很low的代码,还没改,同时,发现了很多缺点,代码冗余等等

双链表的操作

/**
 * @program: day3
 * @description: 双向链表
 * @author: Mr.Mengmeng
 * @create: 2021-02-01 20:32
 **/
/*
    双向链表的操作
 */
//  测试
public class Test {
    public static void main(String[] args) {
        MyDBNode myDBNode = new MyDBNode();
        myDBNode.add("z1");
        myDBNode.add("z2");
        myDBNode.add("z3");
        myDBNode.add("z4");
        myDBNode.add("z5");
        myDBNode.add("z6");
//        System.out.println(myDBNode);
        System.out.println(myDBNode.indexToDelete(6));
        System.out.println(myDBNode);
    }

}

class DBNode {  // 对于每一个结点来说,都有值域,前指针,后指针。
    String value;
    DBNode pre;
    DBNode next;

    public DBNode(String value, DBNode pre, DBNode next) {
        this.value = value;
        this.pre = pre;
        this.next = next;
    }

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

class MyDBNode {
    // 对于每一个双向链表,都有头结点,尾结点,链表的大小。
    DBNode top;
    DBNode end;
    int size;

    // 添加方法
    public boolean add(String str) {
        // 首先判断该表是否是空表
        if (top == null || size == 0) {
            top = new DBNode(str, null, null);
            end = top;
            size++;
            return true;
        }
        // 链表不为空
        DBNode newDBNode = new DBNode(str, end, null);
        end.next = newDBNode;
        end = newDBNode;
        size++;
        return true;
    }

    // 选做:根据下标添加元素
    public String indexAdd(int index, String newStr) {
        // 判断下标是否越界
        if (index < 0 || index > size) throw new IllegalArgumentException("下标越界");
        // 判断空表
        if (top == null || size == 0) {
            top = new DBNode(newStr, null, null);
            end = top;
            size++;
            return newStr;
        }
        // 链表不为空,判断头结点
        if (index == 0) {
            DBNode newdbNode = new DBNode(newStr, null, top);
            top.pre = newdbNode;
            top = newdbNode;
            size++;
            return newStr;
        }
        // 判断 null 结点,尾结点之后添加
        if (index == size) {
            DBNode newDBNode = new DBNode(newStr, end, null);
            end.next = newDBNode;
            end = newDBNode;
            size++;
            return newStr;
        }
        // 判断其他结点,遍历找到被添加结点的前一个结点
        DBNode mid = top;
        int i = 1;
        while (i < index) {
            mid = mid.next;
            i++;
        }
        DBNode newDBNode = new DBNode(newStr, mid, mid.next);
        mid.next = newDBNode;
        mid.next.pre = newDBNode;
        size++;
        return newStr;
    }

    // 删除,根据内容删除
    public String deleteStr(String str) {
        // 判断空表
        if (top == null || size == 0) {
            throw new RuntimeException("MyDBNode is null");
        }
        //   判断删除的是否是唯一元素
        if (size == 1) {
            String oldStr = top.value;
            top = null;
            end = top;
            size--;
            return oldStr;
        }
        // 判断删除的是头结点的内容
        if (top.value.equals(str)) {
            top = top.next;
            top.next.pre = null;
            size--;
            return str;
        }
        // 判断删除的是尾结点的内容
        if (end.value.equals(str)) {
            String oldStr = end.value;
            end.pre.next = null;
            size--;
            return oldStr;
        }
        // 判断删除的是中间结点的内容,遍历删除内容的前一个结点为 mid
        DBNode mid = top;
        while (mid.next != null && !mid.next.equals(str)) {
            mid = mid.next;
        }
        // 没找到
        if (mid.next == null) {
            return null;
        }
        // 找到了,先标记一下
        String oldStr = mid.next.value;
        mid.next = mid.next.next;
        mid.next.next.pre = mid;
        size--;
        return oldStr;
    }

    // 选做:根据下标删除
    public String indexToDelete(int index) {
        // 判断空表
        if (top == null || size == 0) throw new RuntimeException("DBNode is null");
        // 判断下标是否越界
        if (index < 0 || index >= size) throw new IllegalArgumentException("下标越界");
        // 判断删除的是否是唯一元素
        if (size == 1) {
            String oldStr = top.value;
            top = null;
            end = top;
            size--;
            return oldStr;
        }
        // 判断头结点
        if (index == 0) {
            String oldStr = top.value;
            top = top.next;
            top.next.pre = null;
            size--;
            return oldStr;
        }
        // 判断尾结点
        if (index == size - 1) {
            String oldStr = end.value;
            end.pre.next = null;
            end = end.pre;
            size--;
            return oldStr;
        }
        // 判断其他结点
        DBNode mid = top;
        int i = 1;
        while (i<index) {
            mid = mid.next;
            i++;
        }
        DBNode oldNode = mid.next;
        oldNode.pre.next=oldNode.next;
        oldNode.next.pre=oldNode.pre;
        size--;
        return oldNode.value;

    }


    // 修改,根据内容修改
    public String set(String oldStr, String newStr) {
        // 判断空表
        if (top == null || size == 0) throw new RuntimeException("MyDBNode is null");
        // 判断头结点
        if (top.value.equals(oldStr)) {
            top.value = newStr;
            return newStr;
        }
        // 判断中间结点
        DBNode mid = top;
        while (mid.next != null && !mid.next.value.equals(oldStr)) {
            mid = mid.next;
        }
        // 没找到
        if (mid.next == null) {
            return null;
        }
        // 找到了
        mid.next.value = newStr;
        return newStr;

    }

    // 选做:根据下标修改值
    public String indexSet(int index, String newStr) {
        // 判断空表
        if (top == null || size == 0) throw new RuntimeException("DBNode is null");
        // 判断下标是否越界
        if (index < 0 || index >= size) throw new IllegalArgumentException("下标越界");
        // 判断头结点
        if (index == 0) {
            top.value = newStr;
            return newStr;
        }
        // 判断其他结点
        DBNode mid = top;
        int i = 1;
        while (index != i) {
            mid = mid.next;
            i++;
        }
        // 没找到
        if (mid.next == null) {
            return null;
        }
        // 找到了
        mid.next.value = newStr;
        return newStr;
    }

    // 查找
    public boolean find(String str) {
        // 判断空表
        if (top == null || size == 0) throw new RuntimeException("MyDBNode is null");
        // 判断头结点
        if (top.value.equals(str)) {
            return true;
        }
        // 不是头结点,向后遍历,找到被查询结点的前一个结点
        DBNode mid = top;
        while (mid.next != null && !mid.next.value.equals(str)) {
            mid = mid.next;
        }
        // 没找到
        if (mid.next == null) {
            return false;
        }
        // 找到了
        return true;
    }

    // 选做:根据下标查找值
    public String indexToValue(int index) {
        // 判断空表
        if (top == null || size == 0) throw new RuntimeException("MyDBNode is null");
        // 判断下标越界
        if (index < 0 || index >= size) throw new IllegalArgumentException("下标越界");
        // 判断头结点
        if (index == 0) {
            return top.value;
        }
        // 判断其他结点
        DBNode mid = top;
        int i = 1;
        while (index != i) {
            mid = mid.next;
            i++;
        }
        // 没找到
        if (mid.next == null) {
            return null;
        }
        // 找到了
        return mid.next.value;
    }

    // 选做:根据内容查找下标
    public int strToIndex(String str) {
        // 判断空表
        if (top == null || size == 0) throw new RuntimeException("MyDBNode is null");
        // 判断头结点
        if (top.value.equals(str)) {
            return 0;
        }
        // 判断其他结点
        DBNode mid = top;
        int i = 1;
        while (mid.next != null && !mid.next.value.equals(str)) {
            mid = mid.next;
            i++;
        }
        // 没找到
        if (mid.next == null) {
            return -1;
        }
        return i;
    }

    @Override
    public String toString() {
        return "{" +
                "top=" + top +
                '}';
    }
}

​ 可能写的啰嗦了一点,但是只有自己去动手实现更好的理解链表。

快慢指针

​ (第一次听到这个名字,便去学习了一下)

	快慢指针,双指针,表示的是,有两个指针,一个是快指针,每次向后移动两步,一个是慢指针,每次向后移动一步。快慢指针一般应用在带环的链表中。
	那么,我愚蠢的问题又来了...为什么快指针不一次性走三步呢?
	然后就 google 搜索,在 leecode 第141道题中找到解。快指针可以走很多步,那么,同样,遍历次数就会增多,慢指针取1,所以快指针取2,可以最小化算法的运行时间。
三道应用题:
1.求链表的中间元素
public class Demo1 {
    public static void main(String[] args) {
        Node node1 = new Node("zs", null);
        Node node2 = new Node("ls", node1);
        Node node3 = new Node("ww", node2);
        Node node4 = new Node("zl", node2);

        // zl --》 wu --》 ls --》 zs
//        List list = new ArrayList();
//        int size = list.size();
//        int tag = size / 2;
//        System.out.println(list.get(tag));
        // 太慢了,可以用快慢指针
        Node f = node4;
        Node l = node4;
        while (f.next != null && f.next.next != null) {
            // 快指针走两步,慢指针走一步
            f=f.next.next;
            l=l.next;
        }
        // 跳出循环的条件,f 已经接近于链表的尾部
        // l 已经是要查找的中间结点
    }
}

class Node {
    String value;
    Node next;

    public Node(String value, Node next) {
        this.value = value;
        this.next = next;
    }
}
2.判断链表中是否有环(circle),判断环的起始位置
/*
    判断链表中是否有环
 */
public class Demo2 {
    public static void main(String[] args) {
        Node node1 = new Node("1", null);
        Node node2 = new Node("2", node1);
        Node node3 = new Node("3", node2);
        Node node4 = new Node("4", node3);
        Node node5 = new Node("5", node4);
        Node node6 = new Node("6", node5);
        Node node7 = new Node("7", node6);
        Node node8 = new Node("8", node7);

        // 8 7 6 5 4 3 2 1
        node1.next = node5;

        Node f = node7;
        Node l = node7;
        while (f.next != null && f.next.next != null) {
            f = f.next.next;
            l = l.next;
            if (f == l) {
                // 代表,快指针和慢指针重合
                break;
            }
        }

        if (f == l) {
            System.out.println("有环");
        } else { // 要么就是走完了
            System.out.println("没环");
        }


        f = node7;
        while (f != l) {
            f = f.next;
            l = l.next;
        }

        // 环的起始位置
        System.out.println(f.value);
    }
}
3.反转单链表
/*
    反转单链表
 */
public class Demo3 {
    public static void main(String[] args) {
        Node node1 = new Node("1", null);
        Node node2 = new Node("2", node1);
        Node node3 = new Node("3", node2);
        Node node4 = new Node("4", node3);
        Node node5 = new Node("5", node4);
        Node node6 = new Node("6", node5);
        Node node7 = new Node("7", node6);

        // 7 6 5 4 3 2 1
        // 1 2 3 4 5 6 7

        // 头插法 尾插法
        Node relinked = reLinked(node7);
        System.out.println(relinked.toString());
    }

    private static Node reLinked(Node node7) {
        Node relinked = null;

        // 遍历结点
        Node mid = node7;
        // 遍历结点的下一个结点不为空
        while (mid.next != null) {

            // 记录遍历结点的下一个结点,(保存正序序列,以免丢失)
            Node linkedNext = mid.next;  // 维护原来的链表

            // 遍历的结点采用“头插法”,插入反序链表
            mid.next = relinked;
            // 反序链表的头结点前移
            relinked = mid;
            // mid 指向正序链表
            mid = linkedNext;

        }
        // 处理最后一个正序结点
        mid.next = relinked;
        relinked = mid;


        return relinked;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值