单链表增删改查(Java)

1.单链表特征:

        1.1.有一个头结点, 遍历必须从头结点开始

        1.2.单向导通, 也就是只能从前向后遍历, 不能反过来

        1.3.最后一个结点指向null

        1.4.由第一点可以知道, 单链表的查询效率是不够快的, 因为每次查询都需要从头结点开始

        1.5.删除和插入元素的效率高

以下就是一个单链表

2.单链表的代码构成

2.1.Node.java(结点)

/*
    使用了泛型, 这样可以让链表储存的数据更加多元化
*/
public class Node<T> {
    public T data;
    public Node<T> next;

    public Node(T data) {
        this.data = data;
    }
}

2.2.Linked.java(用于构成链表)

public class Linked<T> {
    private Node<T> head = null;
}

3.增删改查实现

3.1.增

3.1.1.头插入法

一开始head是null, 也就是第一次插入node, 这时候直接让head = node即可   

public void addHead(T data) {
    Node<T> node = new Node<>(data);
    if (head == null) {
        head = node;
    }
}

准备将node插入链表

已经将node插入链表
已经将node插入链表

 如果不是第一次插入结点, 则要将node.next = head, head = node, 这样就可以将结点插入到第一个位置

public void addHead(T data) {
    Node<T> node = new Node<>(data);
    if (head == null) {
        head = node;
    } else {
        node.next = head;
        head = node;
    }
}
准备插入node2结点

已经插入node2结点

3.1.2.尾插入法

尾插入法第一个结点插入时和头插入法是一样的, 这里就不再讲了, 这里只讲插入第n个结点的方法

因为要把node插入到最后一个, 所以要找到链表的尾部进行插入, 寻找链表尾部的办法就是从头结点一个一个判断下去, 看看next是否位null

以该链表为例:

首先我们需要一个临时变量用于寻找最后一个结点, 这里命名为temp, 并且指向和head相同的对象, temp = head

再对temp向下迭代, 让temp = temp.next, 也就是自己等于自己的下一个, 达到向下迭代的目的, 而迭代停止的条件是, 当已经没有下一个时, 即temp.next = null时

这时temp.next == null, 这时候可以结束迭代, 这时就可以插入新的node了, 将temp.next = node即可

具体代码:

public void addTail(T data) {
    Node<T> node = new Node<>(data);

    // 头为空, 代表链表为空, 直接将头改为新结点
    if (head == null) {
        head = node;
    } else {

        // 当头结点不为空, 寻找最后的结点, 将新结点插入到最后结点的下一个
        Node<T> temp = head;

        // 寻找最后一个结点
        while (temp.next != null) {
            temp = temp.next;
        }
        temp.next = node;
    }
}

3.2.删

删除分为三种情况:

3.2.1.删除的是第一个结点

直接将head = head.next, 相当于直接跳过第一个结点, 当一个结点不被引用时它会被系统回收

3.2.2.删除的是其他结点

需要使用临时变量temp进行查找, 一个一个向后寻找, 知道找到或找到null则结束

注意: 这里要判断temp.next.data中的数据是否相等, 因为要通过上一个结点才能删除该结点

例如此时要删除的结点是node2, 这时temp.next.data == node2.data

只需要将temp.next = temp.next.next, 这时node2就被跳过了

 具体代码:

public void delete(T target) {
    // 头结点下一个为空, 且目标就是头结点, 直接清空链表
    if (head.next == null && target.equals(head.data)) {
        head = null;
        return;
    }

    // 若不止一个结点, 且头结点就是目标结点
    if (target.equals(head.data)) {
        // 直接跳过头结点, 即删掉头结点
        head = head.next;
    } else {
        // 若头结点不是目标
        Node<T> temp = head;
        while (true) {

            // 找到目标
            if (target.equals(temp.next.data)) {
                // 进行删除(跳过目标结点)
                temp.next = temp.next.next;
                break;
            }
            
            // 若没找到, 继续向下寻找
            temp = temp.next;
        }
    }
}

3.3.改

寻找符合要求的结点, 将其值修改为新的值, 假设node1就是要修改的结点, temp.data = newData

具体代码:

public void update(T target, T newData) {
    // 使用临时结点进行寻找目标结点
    Node<T> temp = head;
    while (temp != null) {

        // 当找到目标结点时
        if (temp.data.equals(target)) {
            // 更换结点值即可
            temp.data = newData;
            break;
        }
        
        // 若未找到, 继续向下寻找
        temp = temp.next;
    }
}

3.4.查

3.4.1.遍历链表

和查找目标结点做法类似, 用temp临时结点一个一个向下遍历输出即可, 直到遇到null停止遍历

具体代码:

public void show() {
    Node<T> temp = head;
    while (temp != null) {
        System.out.print(temp.data + " ");
        temp = temp.next;
    }
}

3.4.2.通过值获得该结点

用temp结点向下查找符合条件的结点, 进行返回, 若循环中没有返回, 则返回null

public Node<T> getNode(T target) {
    Node<T> temp = head;
    while (temp != null) {

        // 找到目标, 返回当前结点
        if (temp.data.equals(target)) return temp;

        // 没找到继续向下找
        temp = temp.next;
    }
    
    // 否则返回null
    return null;
}

4.测试结果:

public class Main {
    public static void main(String[] args) {
        Linked<Integer> l = new Linked<>();
        l.addTail(1);
        l.addTail(2);
        l.addTail(3);
        l.addHead(4);
        l.addHead(5);
        l.addHead(6);
        l.delete(3);
        l.delete(4);
        l.show();
    }
}

运行结果:

6 5 1 2 

可以看到运行结果是没问题的 

5.全部代码

为了方便理解, 没有对成员变量进行封装, 直接采用public

1.Node.java

public class Node<T> {
    public T data;
    public Node<T> next;

    public Node(T date) {
        this.data = date;
    }
}

2.Linked.java

public class Linked<T> {
    private Node<T> head = null;

    /**
     * 通过目标查询相应的结点, 并返回
     * 未找到返回null
     *
     * @param target 目标
     * @return 查询到的结点
     */
    public Node<T> getNode(T target) {
        Node<T> temp = head;
        while (temp != null) {
            if (temp.data.equals(target)) {
                return temp;
            }
            temp = temp.next;
        }
        return null;
    }


    /**
     * 头插入法
     * 将结点插入第一个位置, 效率较高
     *
     * @param date 数据
     */
    public void addHead(T date) {
        Node<T> node = new Node<>(date);
        if (head == null) {
            head = node;
        } else {
            node.next = head;
            head = node;
        }
    }

    /**
     * 尾插入法
     * 将结点插入到最后一个位置, 效率较低
     *
     * @param date 数据
     */
    public void addTail(T date) {
        Node<T> node = new Node<>(date);

        // 头为空, 代表链表为空, 直接将头改为新结点
        if (head == null) {
            head = node;
        } else {

            // 当头结点不为空, 寻找最后的结点, 将新结点插入到最后结点的下一个
            Node<T> temp = head;

            // 寻找最后一个结点
            while (temp.next != null) {
                temp = temp.next;
            }

            temp.next = node;
        }
    }

    /**
     * 更新数据
     *
     * @param target  目标结点
     * @param newData 新数据
     */
    public void update(T target, T newData) {
        Node<T> temp = head;
        while (temp != null) {
            if (temp.data.equals(target)) {
                temp.data = newData;
                break;
            }
            temp = temp.next;
        }
    }

    /**
     * 删除结点
     *
     * @param target 目标结点
     */
    public void delete(T target) {

        // 头结点下一个为空, 代表只有头结点一个, 直接清空链表
        if (head.next == null) {
            head = null;
            return;
        }

        // 若不止一个结点, 且头结点就是目标结点
        if (target.equals(head.data)) {
            // 直接跳过头结点, 即删掉头结点
            head = head.next;
        } else {
            // 若头结点不是目标
            Node<T> temp = head;
            while (true) {
                // 寻找目标
                if (target.equals(temp.next.data)) {
                    temp.next = temp.next.next;
                    break;
                }
                temp = temp.next;
            }
        }
    }

    public void show() {
        Node<T> temp = head;
        while (temp != null) {
            System.out.print(temp.data + " ");
            temp = temp.next;
        }
    }
}

 3.Main.java

public class Main {
    public static void main(String[] args) {
        Linked<Integer> l = new Linked<>();
        l.addTail(1);
        l.addTail(2);
        l.addTail(3);
        l.addHead(4);
        l.addHead(5);
        l.addHead(6);
        l.delete(3);
        l.delete(4);
        l.show();
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值