数据结构与算法学习笔记(三)单向链表

本文详细介绍了单向链表的概念,包括链表、结点、数据域和指针域等核心概念,并探讨了单链表与顺序存储结构的优缺点。此外,还分享了四道常见的链表面试题,如计算有效结点数量、找倒数第k个结点、链表反转和从尾到头打印链表等。
摘要由CSDN通过智能技术生成

一. 几个概念

0x01 链表

  链表是一种物理存储单元非连续非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的。链表是以结点的方式存储的,是链式存储。结点可以在运行时动态生成。链表是有序的列表,但其在内存中的存储是非连续、非顺序的。

0x02 结点

  在链表数据结构中,我们把一个数据元素的存储映像称为结点(Node)。而一个结点包含存储数据元素的两部分信息:数据域(Data)和指针域(Next)。

0x03 数据域、指针域

数据域:存储数据元素信息的域;
指针域:存储直接后继位置的域,指向下一个结点。

0x04 直接前驱元素和直接后继元素
  • 对于线性存储结构,假设线性表记为 ( 1 , 2 , . . . , n − 1 , n , n + 1... ) (1,2,...,n-1,n,n+1...) (1,2,...,n1,n,n+1...)
    数据元素 n n n直接前驱元素 n − 1 n-1 n1
    数据元素 n n n直接后继元素 n + 1 n+1 n+1
  • 对于链表存储结构,如下图所示:
    在这里插入图片描述

head.next表示为头结点head的后继结点;而head则为head.next的前驱结点

0x05 链表分带头结点的链表和没有头结点的链表

在这里插入图片描述
在这里插入图片描述

  • 首先,无论链表是否为空,头指针均不为空;即链表一旦被创建,则头指针便指向了它,头指针是链表的必要元素。头指针存放的是链表第一个结点的地址。
  • 对于包含头结点的单链表,头指针存放的是头结点的存放地址,而头结点也包含数据域(data)和指针域(next),但头结点的数据域一般不存储任何信息,头结点的指针域包含的是首结点的地址。
  • 对于不包含头结点的单链表,头指针存放的就是首节点的地址。
  • 首节点:是存放链表中第一个有效元素的结点。
  • 头结点是为了操作的统一和方便而引出的,放在第一个元素结点之前。有了头结点则在首节点前增加、删除元素就和其他结点的操作统一了。头结点不一定是链表必需要素。

二. 单链表结构与顺序存储结构的优缺点

1.存储分配方式

  • 顺序存储结构用一段连续存储单元依次存储线性表的数据元素
  • 单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素

2.时间性能

  • 查找
    – 顺序存储结构o(1)
    – 单链表o(n)
  • 插入和删除
    – 顺序存储结构需要平均移动表长一半的元素,时间复杂度o(n)
    – 单链表在找到位置的指针后,插入和删除时间复杂度仅为o(1)

2.空间性能

  • 顺序存储结构需要预分配存储空间,分大了,浪费,分小了易发生上溢
  • 单链表不需要预分配存储空间,只要有就可以分配,元素个数也不受限制

三. 几道面试题

面试题1:获取单链表的有效结点个数(如果是带头结点的链表,不统计头结点)
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;
    }
面试题2:查找单链表中的倒数第k个结点【新浪面试题】
/*
        思路:①编写一个方法,接收head结点,同时接收一个index
             ②index表示倒数第index个结点
             ③先把链表从头到尾遍历,得到链表的总长度 getLength
             ④得到size后,从链表的第一个结点开始,遍历(size-index)个,就可以得到
             ⑤找到,则返回该结点,否则返回null
     */
    public static HeroNode findLastIndexNode(HeroNode head, int index){
   
        //判断链表为空,返回null
        if (head.next == null) {
   
            return null; //没找到
        }
        //第一个遍历得到链表的长度(结点个数)
        int size = getLength(head);
        //第二次遍历size-index位置,就是倒数第index个结点
        //先做一个index的校验
        if (index <= 0 || index > size) {
   
            return null;
        }
        HeroNode cur = head.next;
        for(int i = 0; i < size-index; i++){
   
            cur = cur.next;
        }
        return cur;
    }
面试题3:单链表的反转【腾讯面试题】
/*
        思路:①先定义一个结点reverseHead = new HeroNode();
              ②从头到尾遍历原来的链表,每遍历一个结点,就将其取出,并放在新链表的最前端
              ③将原来的链表的head.next = reverseHead.next
     */
    public static void reverseList(HeroNode head){
   
        //如果当前链表为空,或者只有一个结点,无需反转直接返回
        if (head.next == null || head.next.next == 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值