单向链表代码实现

链表是有序的列表,以节点的方式进行存储,但在内存中的各节点地址并不连续。其中单链表的特点是每个节点包含data域(存储数据)和next域(指向下一个节点)。单链表分带头结点链表和不带头结点的链表,根据实际需求来确定。
这里用代码实现带头结点的单链表:
1.先自定义一个节点:

class Node {
    int data;//节点存储的数据
    Node next;//指向下一个节点

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

    //打印节点
    @Override
    public String toString() {
        return "Node{" +
                "data=" + data +
                '}';
    }
}

2.实现自定义单链表
并给出了一些单链表算法题的实现

/**
 * 自定义单向链表
 */
public class MyLinkedList {
    //定义一个头节点,该节点不存储任何数据,只用来指向第一个节点
    private Node head = new Node(0);
    /**
     * 添加节点
     * @param node
     */
    public void add(Node node) {
       //定义一个辅助节点,用来遍历链表
        Node tmp = head;
        //先循环遍历到链表的最后一个位置
        while (tmp.next != null){
            tmp = tmp.next;
        }
        //经过循环之后,tmp指向最后一个节点,再将最后一个节点的next指向要添加的节点
        tmp.next = node;
    }

    /**
     * 遍历节点
     */
    public void list() {
        //判断链表是否为空
        if (head.next == null) {
            System.out.println("链表为空");
            return;
        }
        //定义一个辅助节点,用来遍历链表
        Node tmp = head;
        while (tmp.next != null) {
            tmp = tmp.next;
            System.out.println(tmp);
        }
    }

    /**
     * 插入节点
     *
     * @param srcNode 表示要在哪一个节点后面插入新节点
     * @param afterNode 要插入的新节点
     */
    public void insert(Node srcNode, Node afterNode) {
        if (head.next == null) {
            System.out.println("链表为空");
            return;
        }
        //找到需要修改的编号
        Node tmp = head.next;
        boolean flag = false;
        while (true) {
            if (tmp == null) {
                break;//已遍历完链表
            }
            if (tmp.data == srcNode.data) {
                flag = true;//找到了要修改的节点
                break;
            }
            tmp = tmp.next;
        }
        if (flag) {
            //此时tmp就是指向要插入的位置前一个节点,于是在tmp节点后面插入节点
            //此处是一个断链再合链的常规操作
            afterNode.next = tmp.next;
            tmp.next = afterNode;
        } else {
            System.out.printf("没有找到数据为%d的节点", srcNode.data);
        }
    }

    /**
     * 删除节点
     *
     * @param node
     */
    public void delete(Node node) {
    	/*
        因为这里是单向链表,在删除一个节点时,因为无法知道一个节点的前一个节点是哪个,所有只能在遍历到该节点的前一个节点时,
        进行删除操作        
         */
        //所以这里开始指向头结点,不能开始就指向第一个节点
        Node tmp = head;
        while (tmp.next != null) {
            if (tmp.next == node) {//找到了要删除的节点
                tmp.next = tmp.next.next;
                return;//结束方法
            }
            tmp = tmp.next;
        }
        //循环退出,说明没有找到要删除的节点
        System.out.println("要删除的节点不存在");
    }

    /**
     * 求单链表中节点的个数
     *
     * @return
     */
    public int getLength() {
        if (head.next == null) {
            return 0;
        }
        Node tmp = head.next;
        int length = 0;
        while (tmp != null) {
            length++;
            tmp = tmp.next;
        }
        return length;
    }

    /**
     * 求单链表中倒数第index个节点
     *
     * @param index
     * @return
     */
    public Node getLastIndexNode(int index) {
        //如果链表为空,则返回null
        if (head.next == null) {
            return null;
        }

        //对index进行校验
        if (index <= 0 || index > this.getLength()) {
            return null;
        }
        Node tmp = head.next;
        for (int i = 0; i < (this.getLength() - index); i++) {
            tmp = tmp.next;
        }
        return tmp;
    }

    /**
     * 反转链表
     */
    public void reverse() {
        /*
        思路:从第二个节点开始,分别依次将节点放到第一个节点前面
        因此,1.先定义一个tmp指针用于遍历节点
        2.将每个节点放到第一个节点之前,要也就是要插入到head和第一个节点之间,
        所以将第一个节点赋给待插入节点的next,再将带插入节点赋给head的next即可
         */
        //链表为空或者链表只有一个节点
        if (head.next == null || head.next.next == null) {
            return;
        }
        Node tmp = head.next.next;//用于遍历节点,从第二个节点开始
        head.next.next = null;//由于第一个节点反转之后会成为最后一个节点,所以将第一个节点的next置为null
        Node next = null;//用于记录所遍历节点的next指向的下一个节点
        while (tmp != null){
            next = tmp.next;
            tmp.next = head.next;//将tmp.next指向第一个节点
            head.next = tmp;
            tmp = next;
        }
    }

    /**
     * 逆序打印,不改变链表原有结构
     */
    public void reversePrint(){
        if(head.next == null){
            return;//空链表,不打印
        }
        //创建一个栈,用于保存链表中的节点
        Stack<Node> stack = new Stack<>();
        //遍历节点,依次将节点压入栈中
        Node tmp = head.next;
        while (tmp != null){
            stack.push(tmp);
            tmp = tmp.next;
        }
        //再将栈中的元素依次弹栈
        while (stack.size() > 0){
            Node node = stack.pop();
            System.out.println(node);
        }
    }

    /**
     * 递归实现链表倒序输出
     */
    public void reversePrint2(){
        print(head.next);
    }
    private void print(Node node){
        if(node == null){
            return;
        }
        print(node.next);
        System.out.println(node);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值