单链表(增删改查)

数据结构:单链表(增删改查)

准备一个结点类

class HeroNode {
    public int no;
    public String name;
    public String nickName;
    public HeroNode next; //指向下一个结点

    public HeroNode(int no, String name, String nickName) {
        this.no = no;
        this.name = name;
        this.nickName = nickName;
    }
}

准备一个链表类

class SingleLinkedList {
    //先初始化头结点
    private HeroNode head = new HeroNode(0, "", "");
    //定义一个尾结点,用于添加结点
    private HeroNode tail = head;
}

add()

public void add(HeroNode heroNode) {
        tail.next = heroNode;
        tail = heroNode;
}

按照结点编号升序插入链表

public void addByOrder(HeroNode heroNode) {
        HeroNode temp = head; //temp指向要比较的结点的前一个结点
        boolean flag = false; //标志添加的编号是否存在,默认false
        //寻找添加位置
        while (true) {
            if (temp.next == null) {//没找到插入位置,直接插入到链表尾
                break;
            }
            if (temp.next.no > heroNode.no) {//下一个结点no大于插入的no,前一个结点no小于插入的no
                break;
            } else if (temp.next.no == heroNode.no) {//说明希望添加的heroNode的编号已经存在
                flag = true;
            }
            temp = temp.next;//后移
        }
        //判断flag的值
        if (flag) {//编号存在,不能添加
            System.out.printf("准备插入的英雄编号%d 已经存在了,不能加入\n", heroNode.no);
        } else {//编号不存在,插入到链表中,temp指针后面
            heroNode.next = temp.next;
            temp.next = heroNode;
        }
    }

注意

如果链表中已经存在要插入的结点,则不能插入,并给出提示

update(HeroNode newHeroNode)

public void update(HeroNode newHeroNode) {
        //判断链表是否为空
        if (head.next == null) {
            System.out.println("链表为空!");
            return;
        }
        //找到需要修改的结点,根据no编号
        //定义遍历指针
        HeroNode temp = head;
        while (temp != null && temp.no != newHeroNode.no) {
            temp = temp.next;
        }
        if (temp == null) {
            System.out.printf("没有找到编号 %d 的结点,不能修改\n", newHeroNode.no);
        } else {
            temp.name = newHeroNode.name;
            temp.nickName = newHeroNode.nickName;
        }
    }

del(int no)

思路:找到待删除结点的前一个结点,temp指向要比较的结点的前一个位置,所以比较时是,temp.next.no == delNo

public void del(int no) {
        //判断链表是否为空
        if (head.next == null) {
            System.out.println("链表为空!");
            return;
        }
        //定义指针
        HeroNode temp = head;
        while (temp.next != null && temp.next.no != no) {
            temp = temp.next;
        }
        if (temp.next == null) {//没有找到删除结点,temp就移动到了链尾
            System.out.printf("没有找到编号 %d 的结点,不能删除\n", no);
        } else {//找到删除结点,temp指向链表中间
            temp.next = temp.next.next;
        }
}

打印链表

public void list() {
        //先判断链表是否为空
        if (head.next == null) {
            System.out.println("链表为空");
            return;
        }
        HeroNode temp = head.next;
        while (temp != null) {
            //输出结点信息
            System.out.println(temp);
            //将temp后移
            temp = temp.next;
        }
}

基本面试题

获取链表结点个数

public static int getLength(HeroNode head) {
        if (head.next == null) {
            return 0;
        }
        int length = 0;
        //定义一个遍历指针
        HeroNode cur = head.next;
        while (cur != null) {
            length++;
            cur = cur.next;
        }
        return length;
    }

获取单链表中的倒数第k个结点

思路:

1. 先获取链表长度length
2. 得到length后,指针只需从第一个结点向后移动 length-index 次
public static HeroNode getLastIndexOf(HeroNode head, int index) {
        if (head.next == null) {
            return null;
        }
        int length = getLength(head);
        if (index <= 0 || index > length) {
            return null;
        }
        HeroNode cur = head;
        for (int i = 0; i <= length - index; i++) {
            cur = cur.next;
        }
        return cur;
    }

反转链表

遍历法

思路:

1. 创建一个新的头节点
2. 遍历原有链表,将遍历到的每个结点插入到新创建的结点的后面
public static void reverseList(HeroNode head) {
        //如果链表为空或者链表只有一个结点,就无需反转,直接返回
        if (head.next == null || head.next.next == null) {
            return;
        }
        HeroNode reverseHead = new HeroNode(0, "", "");
        HeroNode cur = head.next;
        //临时保存要插入反转链表的结点
        HeroNode curNext;
        //遍历原来的链表,每遍历一个结点,就将这个结点插入到新链表的头部
        while (cur != null) {
            curNext = cur.next;
            cur.next = reverseHead.next;
            reverseHead.next = cur;
            cur = curNext;
        }
        head.next = reverseHead.next;
    }

利用Stack实现

思路:

1. 遍历结点,并压入栈中
2. 循环取出栈顶结点,并将其next指向新的栈顶结点
public static void reverse(HeroNode head) {
        if (head.next == null || head.next.next == null) {
            return;
        }
        Stack<HeroNode> stack = new Stack<>();
        HeroNode cur = head.next;
    	//遍历结点并压入栈中
        while (cur != null) {
            stack.push(cur);
            cur = cur.next;
        }
        
    	//先取出一个结点,使next指向栈顶的结点
        head.next = stack.pop();
        head.next.next = stack.peek();
        while (stack.size() > 0) {
            //循环取出结点,并next指向栈顶结点,最后一个结点指向null
            HeroNode node = stack.pop();
            if (stack.size() == 0) {
                node.next = null;
                break;
            }
            node.next = stack.peek();
        }
    }

逆序打印链表

思路:

1. 同样是借助栈,遍历结点压入栈
2. 取出栈顶结点并打印
public static void reversePrint(HeroNode head) {
        if (head.next == null) {
            return;
        }
        Stack<HeroNode> stack = new Stack<>();
        HeroNode cur = head.next;
        //将链表所有结点压入栈中,需要注意的是,jdk1.8,栈的最大深度为12000
        while (cur != null) {
            stack.push(cur);
            cur = cur.next;
        }
        //循环出栈,打印出栈的结点
        while (stack.size() > 0) {
            System.out.println(stack.pop());
        }
    }

合并两个有序的链表,新的链表同样有序

思路:

  1. 创建一个新的头结点

  2. 从头到尾遍历两个链表,比较两链表中指针指向的结点大小,小的先插入新的链表中,然后移动指针

    取下一个结点和另外一个链表中指针指向的结点比较

  3. 一旦有一个链表遍历完成,则判断哪个链表不为空,就将新链表的尾部指向不为空链表中指针指向的下一个结点

注意

​ 如果有一个链表为空,就将新链表头结点指向这个链表的第一个结点

​ 如果两个链表都为空,就直接指向null返回

public static HeroNode concatList(HeroNode head1, HeroNode head2) {
        HeroNode newHead = new HeroNode(0, "", "");
        if (head1.next == null && head2.next == null) {
            newHead.next = null;
            return newHead;
        }
        HeroNode tail = newHead;
        if (head1.next == null && head2.next != null) {
            newHead.next = head2.next;
        }
        if (head1.next != null && head2.next == null) {
            newHead.next = head1.next;
        }
        HeroNode cur1 = head1.next;
        HeroNode cur2 = head2.next;
        while (cur1 != null && cur2 != null) {
            if (cur1.no <= cur2.no) {
                tail.next = cur1;
                cur1 = cur1.next;
            } else {
                tail.next = cur2;
                cur2 = cur2.next;
            }
            tail = tail.next;
        }
        if (cur1 == null) {
            tail.next = cur2;
        } else {
            tail.next = cur1;
        }
        return newHead;
    }
posted @ 2021-03-05 09:36  编程の小白  阅读(232)  评论(0编辑  收藏  举报