数据结构与算法详细解析之单链表结构(含常见面试题)

一、单链表结构:链表是由N个Node节点构成,每个Node节点包括data域及next域,由Next域指向下一个Node节点对象;所以,链表这一结构特性决定了链表再内存中的数据不是连续存储的,数据分布在内存中的多个内存块中下图为链表在内存结构中的示意图:

注:关于双向链表节点解析及常见面试题分析见博客:https://blog.csdn.net/weixin_54513300/article/details/121321081

二、链表分类:带头结点链表/与不带头结点链表,下图为带头结点链表结构示意图:

注意:头结点不存储具体的数据,仅仅表示单链表的头结点;

 三、测试案例:创建链表,并向链表中存储水浒英雄

1)创建HeroNode节点类,用以存储每个英雄及别名:

//定义一个HeroNode,每个HeroNode为一个对象
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;
    }
    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickName='" + nickName + '\'' +
                '}';
    }
}

2)定义单链表存储结构,并定义add方法及遍历方法:

//定义单链表存储数据
class SingleLinkedList{
    //初始化头结点
    private HeroNode head = new HeroNode(0,"","");
    //定义向链表中添加Node节点的方法
    //思路:找到链表中的最后一个节点(node.next=NULL)后,令node.next=new HeroNode
    public void add(HeroNode heroNode){
        HeroNode temp = head;
        while (true){
            //找到链表最后一个节点后终止循环
            if (temp.next==null){
                break;
            }
            temp = temp.next;
        }
        //循环结束后temp为最后一个节点,此时temp.next=heroNode即可
        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;
        }
    }
}
3)Demo测试
public static void main(String[] args) {
        SingleLinkedList list = new SingleLinkedList();
        HeroNode node1 = new HeroNode(1, "宋江", "及时雨");
        HeroNode node2 = new HeroNode(1, "吴用", "智多星");
        HeroNode node3 = new HeroNode(1, "林冲", "豹子头");
        list.add(node1);
        list.add(node2);
        list.add(node3);
        //输出链表中的存储数据
        list.list();
    }

三、单链表常见面试题 

1)求单链表中有效节点个数:

//定义一个方法获取节点数量
    public static int getNodeNum(HeroNode head){
        if (head.next==null){
            return 0;
        }
        int length = 0;
        HeroNode temp = head.next;
        while (temp!=null){
            length++;
            temp=temp.next;
        }
        return length;
    }
//demo测试:
public static void main(String[] args) {
        SingleLinkedList list = new SingleLinkedList();
        HeroNode node1 = new HeroNode(1, "宋江", "及时雨");
        HeroNode node2 = new HeroNode(1, "吴用", "智多星");
        HeroNode node3 = new HeroNode(1, "林冲", "豹子头");
        list.add(node1);
        list.add(node2);
        list.add(node3);
        //输出链表中的存储数据
        list.list();
        int nodeNum = list.getNodeNum(list.getHead());
        System.out.println("该链表节点数量:"+nodeNum);
    }

 2)查找单链表中倒数第K个节点:

在第一道题基础上就很简单了,直接说说思路:先得到链表总的节点数量Num,然后获取该链表的第Num-k节点就可以了;

3)单链表的反转:

public static void reversetList(HeroNode head) {
        //如果当前链表为空,或者只有一个节点,无需反转,直接返回
        if(head.next == null || head.next.next == null) {
            return ;
        }
        //定义一个辅助的指针(变量),帮助我们遍历原来的链表
        HeroNode cur = head.next;
        HeroNode next = null;// 指向当前节点[cur]的下一个节点
        HeroNode reverseHead = new HeroNode(0, "", "");
        //遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead 的最前端
        //动脑筋
        while(cur != null) {
            next = cur.next;//先暂时保存当前节点的下一个节点,因为后面需要使用
            cur.next = reverseHead.next;//将cur的下一个节点指向新的链表的最前端
            reverseHead.next = cur; //将cur 连接到新的链表上
            cur = next;//让cur后移
        }
        //将head.next 指向 reverseHead.next , 实现单链表的反转
        head.next = reverseHead.next;
    }

4)从尾到头打印单链表(反向遍历):

//反向遍历单链表
    public static void revergeList(SingleLinkedList list,int num){
        HeroNode head = list.getHead();
        if (head.next==null){
            System.out.println("链表为空");
            return;
        }
        for (int i = num-1; i >= 0 ; i--) {
            HeroNode node = list.getNode(list, i);
            System.out.println(node);
        }
    }

//定义一个方法获取第K个Node节点
    public static HeroNode getNode(SingleLinkedList list,int K){
        HeroNode head = list.getHead();
        if (head.next==null){
            return null;
        }
        int num = 0;
        HeroNode temp = head.next;
        while (temp !=null){

            if (num == K){
                return temp;
            }
            if (num==getNodeNum(head)){
                break;
            }
            temp=temp.next;
            num++;
        }
        return null;
    }

测试结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值