数据结构与算法-单链表面试题

题一:获取单链表节点的个数

思路

在HeroNode类中写一个方法public static int getLength(HeroNode head)获取节点个数。如果是带头节点就不统计头节点。

如果head节点的next为null就返回0.否则定义一个length变量用于计数,定义一个辅助变量current,current=head.next,然后循环中只要current不为null就把length加1,再把current后移。循环结束后返回的length就是节点的个数。

方法代码:

//获取单链表的节点个数,如果是带头节点的链表就不统计头节点
    public static int getLength(HeroNode head) {
        if (head.next == null) {
            //为空链表则直接返回0
            return 0;
        }
        int length = 0;//统计有效节点个数
        //辅助变量用于遍历
        HeroNode current = head.next;
        while (current != null) {
            length++;
            current = current.next;
        }
        return length;
    }

由于SingleLinkedList中头节点是私有的,所以要获取头节点还需要在SingleLinkedList类中写一个方法获取头节点。

//先初始化头节点,不存放具体数据
    private HeroNode head = new HeroNode(0, "", "");

    //返回头节点
    public HeroNode getHead() {
        return head;
    }

在main方法中

System.out.println("节点个数:" + getLength(singleLinkedList1.getHead()));

运行结果:

题二:查找单链表的倒数第k个节点

思路

编写一个方法,接收head节点,同时接收index(倒数第index个节点)。先把链表从头到尾遍历,得到链表总长Length。得到Length后,从链表第一个节点开始遍历Length-index个节点。比如总共3个节点,要查倒数第一个节点就从第一个节点开始遍历2个节点。使已经知道要遍历几个节点就用for循环,找到了就返回该节点,找不到就返回null。

方法代码

//获取单链表倒数第K个节点
    public static HeroNode findLastIndexNode(HeroNode head,int index){
        //判断链表是否为空
        if(head.next==null){
            return null;
        }
        //先遍历得到节点个数
        int Length=getLength(head);
        //再遍历到size-index
        if(index<=0||index>Length){
            return null;//不合适的index就返回null
        }
        //定义辅助变量temp
        HeroNode temp=head.next;
        for(int i=0;i<Length-index;i++){
            temp=temp.next;
        }
        return temp;
    }

在main方法中

HeroNode res=findLastIndexNode(singleLinkedList1.getHead(),1);
System.out.println("倒数第1个节点为:"+res);

运行结果:


完整代码:

package com.xjj.linkedlist;

public class LinkedList {
    public static void main(String[] args) {
        //创建节点
        HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
        HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
        HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
        HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
        //创建链表
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        //将节点加入链表
        singleLinkedList.add(hero1);
        singleLinkedList.add(hero2);
        singleLinkedList.add(hero3);
        singleLinkedList.add(hero4);
        //显示链表
        singleLinkedList.list();
        System.out.println("按编号顺序插入");
        SingleLinkedList singleLinkedList1 = new SingleLinkedList();
        //将节点插入链表
        singleLinkedList1.addByOrder(hero1);
        singleLinkedList1.addByOrder(hero4);
        singleLinkedList1.addByOrder(hero2);
        singleLinkedList1.addByOrder(hero3);
        singleLinkedList1.list();
        //测试修改节点
        System.out.println("修改节点");
        HeroNode newHeroNode = new HeroNode(2, "卢", "玉麒麟--");
        singleLinkedList1.update(newHeroNode);
        singleLinkedList1.list();
        //测试删除节点
        System.out.println("删除节点1");
        singleLinkedList1.delete(1);//删除第一个节点
        singleLinkedList1.list();
        System.out.println("删除节点4");
        singleLinkedList1.delete(4);//删除第四个节点
        singleLinkedList1.list();
//        System.out.println("删完");
//        singleLinkedList1.delete(2);//删除第二个节点
//        singleLinkedList1.delete(3);//删除第三个节点
//        singleLinkedList1.list();
        System.out.println("节点个数:" + getLength(singleLinkedList1.getHead()));
        HeroNode res=findLastIndexNode(singleLinkedList1.getHead(),1);
        System.out.println("倒数第1个节点为:"+res);
    }

    //获取单链表的节点个数,如果是带头节点的链表就不统计头节点
    public static int getLength(HeroNode head) {
        if (head.next == null) {
            //为空链表则直接返回0
            return 0;
        }
        int length = 0;//统计有效节点个数
        //辅助变量用于遍历
        HeroNode current = head.next;
        while (current != null) {
            length++;
            current = current.next;
        }
        return length;
    }
    //获取单链表倒数第K个节点
    public static HeroNode findLastIndexNode(HeroNode head,int index){
        //判断链表是否为空
        if(head.next==null){
            return null;
        }
        //先遍历得到节点个数
        int Length=getLength(head);
        //再遍历到size-index
        if(index<=0||index>Length){
            return null;//不合适的index就返回null
        }
        //定义辅助变量temp
        HeroNode temp=head.next;
        for(int i=0;i<Length-index;i++){
            temp=temp.next;
        }
        return temp;
    }
}

//英雄类
class HeroNode {
    public int no;
    public String name;
    public String nickname;
    public HeroNode next;//指向下一个节点

    //构造器
    public HeroNode(int hNo, String hName, String hNickname) {
        this.no = hNo;
        this.name = hName;
        this.nickname = hNickname;
    }

    //重写toString来显示方法
    @Override
    public String toString() {
        return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
    }
}

//管理英雄类
class SingleLinkedList {
    //先初始化头节点,不存放具体数据
    private HeroNode head = new HeroNode(0, "", "");

    //返回头节点
    public HeroNode getHead() {
        return head;
    }

    //添加节点。不考虑编号顺序时,先找到当前链表的最后节点,再将这个节点的next指向新节点
    public void add(HeroNode heroNode) {
        //辅助遍历temp
        HeroNode temp = head;
        //遍历链表找到最后
        while (true) {
            if (temp.next == null) {//找到最后了就退出
                break;
            }
            //没到最后就后移到下一个节点
            temp = temp.next;
        }
        //退出while循环时temp就指向链表最后
        //我们要添加新节点,就将这个最后节点的next指向节点
        temp.next = heroNode;
    }

    //添加节点,考虑编号顺序。也就是插入到链表非末尾位置
    public void addByOrder(HeroNode heroNode) {
        //辅助变量位于添加位置的前一个节点
        HeroNode temp = head;
        boolean flag = false;//标识添加的编号是否存在。如果存在就不能添加了
        while (true) {
            if (temp.next == null) {
                //已经在链表最后,要添加的节点可能已经在链表最后
                break;
            }
            if (temp.next.no > heroNode.no) {
                //temp下一个节点的编号大于要插入的节点编号,就是找到了,要在这个temp后面插入
                break;
            } else if (temp.next.no == heroNode.no) {
                //编号已存在
                flag = true;//编号存在
            }
            temp = temp.next;//后移
        }
        //判断编号是否已存在
        if (flag) {
            System.out.printf("准备插入的编号 %d 已经存在,无法添加\n", heroNode.no);
        } else {
            //新节点插入链表中temp的后面
            heroNode.next = temp.next;
            temp.next = heroNode;//temp后面是新节点
        }
    }

    //根据编号修改节点信息,即编号不能修改
    public void update(HeroNode newHeroNode) {
        //判断链表是否为空
        if (head.next == null) {
            //如果链表为空就不遍历了
            System.out.println("链表为空");
            return;
        }
        //找到需要修改的节点
        //辅助变量
        HeroNode temp = head.next;
        boolean flag = false;//判断是否找到该节点
        while (true) {
            if (temp == null) {
                break;//已经遍历完链表
            }
            if (temp.no == newHeroNode.no) {
                //找到
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //判断是否找到节点
        if (flag) {
            temp.name = newHeroNode.name;
            temp.nickname = newHeroNode.nickname;
        } else {
            System.out.printf("没有找到编号为 %d 的节点\n", newHeroNode.no);
        }
    }

    //删除节点
    public void delete(int no) {
        //判断链表是否为空
        if (head.next == null) {
            //如果链表为空就不遍历了
            System.out.println("链表为空");
            return;
        }
        //找到需要修改的节点
        //辅助变量
        HeroNode temp = head;
        boolean flag = false;//判断是否找到该节点
        while (true) {
            if (temp.next == null) {
                break;//已经遍历完链表
            }
            if (temp.next.no == no) {
                //找到待删除节点的前一个节点
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //判断是否找到节点
        if (flag) {
            temp.next = temp.next.next;
        } else {
            System.out.printf("没有找到编号为 %d 的节点\n", no);
        }
    }

    //显示链表,看有没有成功
    public void list() {
        //判断链表是否为空,如果为空就不遍历了
        if (head.next == null) {
            System.out.println("链表为空");
            return;
        }
        //不为空就遍历
        //使用辅助变量来遍历
        HeroNode temp = head.next;//这里指向的是下一个
        while (true) {
            //看是否到链表最后
            if (temp == null) {
                break;
            }
            //不为空就输出节点信息
            System.out.println(temp);
            //后移
            temp = temp.next;
        }
    }
}

运行结果:

题三:反转单链表

原链表:

反转后:

思路

先定义一个节点reverseHead=newHeroNode(),再遍历原来的链表,遍历一个节点就取出一个节点,放到新链表的最前端。最后使原来链表的head.next=reverseHead.next,就连上了。

一个辅助变量temp,指向要取出的节点之后把temp后移一个然后把节点取出来,把reverseHead节点与刚取出的节点连起来。

如图先把第一个节点获取之后接到reverseHead节点后面,temp已经移到了第二个节点。

再把获取的第二个节点接到reverseHead节点后面,第二个节点的next变成原来的第一个节点。

再把获取的第三个节点接到reverseHead节点后面,第三个节点的next变成原来的第二个节点。

最后把原head节点的next指向reverseHead节点的后面的第一个节点。那么从head节点开始遍历的时候也不会遍历到reverseHead节点。成功实现了链表反转。

关键代码:

//将链表反转
    public static void reverseList(HeroNode head) {
        //当前链表为空或只有一个节点就不需要反转
        if (head.next == null || head.next.next == null) {
            return;
        }
        //定义辅助变量遍历原来的链表
        HeroNode current = head.next;
        HeroNode curNext = null;//指向当前节点current的下一个节点
        HeroNode reverseHead = new HeroNode(0, "", "");
        //遍历原来的链表,遍历一个节点就取出一个节点放在新链表reverseHead最前面
        while (current != null) {
            curNext = current.next;//暂时保存当前节点的下一个节点
            current.next = reverseHead.next;//将current的下一个节点指向新链表的最前端,就是新链表头节点后面的第一个节点
            reverseHead.next=current;//将current连接到新链表上
            current=curNext;//当前节点后移一个
        }
        //while这里结束之后就实现了完整的新链表
        //将head.next指向reverseHead.next
        head.next=reverseHead.next;
    }

在main中:

//测试链表反转

singleLinkedList.list();

System.out.println("反转后:");

reverseList(singleLinkedList.getHead());

singleLinkedList.list();

反转单链表完整代码:

package com.xjj.linkedlist;

public class LinkedList {
    public static void main(String[] args) {
        //创建节点
        HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
        HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
        HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
        HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
        //创建链表
        SingleLinkedList singleLinkedList = new SingleLinkedList();

       //将节点加入链表
        singleLinkedList.add(hero1);
        singleLinkedList.add(hero2);
        singleLinkedList.add(hero3);
        singleLinkedList.add(hero4);
        //测试链表反转
        singleLinkedList.list();
        System.out.println("反转后:");
        reverseList(singleLinkedList.getHead());
        singleLinkedList.list();
    }
    //将链表反转
    public static void reverseList(HeroNode head) {
        //当前链表为空或只有一个节点就不需要反转
        if (head.next == null || head.next.next == null) {
            return;
        }
        //定义辅助变量遍历原来的链表
        HeroNode current = head.next;
        HeroNode curNext = null;//指向当前节点current的下一个节点
        HeroNode reverseHead = new HeroNode(0, "", "");
        //遍历原来的链表,遍历一个节点就取出一个节点放在新链表reverseHead最前面
        while (current != null) {
            curNext = current.next;//暂时保存当前节点的下一个节点
            current.next = reverseHead.next;//将current的下一个节点指向新链表的最前端,就是新链表头节点后面的第一个节点
            reverseHead.next=current;//将current连接到新链表上
            current=curNext;//当前节点后移一个
        }
        //while这里结束之后就实现了完整的新链表
        //将head.next指向reverseHead.next
        head.next=reverseHead.next;
    }
}

//英雄类
class HeroNode {
    public int no;
    public String name;
    public String nickname;
    public HeroNode next;//指向下一个节点

    //构造器
    public HeroNode(int hNo, String hName, String hNickname) {
        this.no = hNo;
        this.name = hName;
        this.nickname = hNickname;
    }

    //重写toString来显示方法
    @Override
    public String toString() {
        return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
    }
}

//管理英雄类
class SingleLinkedList {
    //先初始化头节点,不存放具体数据
    private HeroNode head = new HeroNode(0, "", "");

    //返回头节点
    public HeroNode getHead() {
        return head;
    }

    //添加节点。不考虑编号顺序时,先找到当前链表的最后节点,再将这个节点的next指向新节点
    public void add(HeroNode heroNode) {
        //辅助遍历temp
        HeroNode temp = head;
        //遍历链表找到最后
        while (true) {
            if (temp.next == null) {//找到最后了就退出
                break;
            }
            //没到最后就后移到下一个节点
            temp = temp.next;
        }
        //退出while循环时temp就指向链表最后
        //我们要添加新节点,就将这个最后节点的next指向节点
        temp.next = heroNode;
    }

    //显示链表,看有没有成功
    public void list() {
        //判断链表是否为空,如果为空就不遍历了
        if (head.next == null) {
            System.out.println("链表为空");
            return;
        }
        //不为空就遍历
        //使用辅助变量来遍历
        HeroNode temp = head.next;//这里指向的是下一个
        while (true) {
            //看是否到链表最后
            if (temp == null) {
                break;
            }
            //不为空就输出节点信息
            System.out.println(temp);
            //后移
            temp = temp.next;
        }
    }
}

运行结果


加油加油^_^

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值