LeetCode--线性表(206)

本文详细介绍了线性表的概念,包括顺序表和链表两种表现形式。顺序表用连续的存储单元存储数据,链表则由任意存储单元组成,每个结点包含数据域和指针域。文章还讲解了链表中的头结点和头指针的作用,并以单链表为例阐述了其基本操作原理。此外,文章提供了反转单链表的Python和Java解题思路。
摘要由CSDN通过智能技术生成

线性表

1.定义:

零个或多个数据元素的有限序列。
【线性表】:某类元素的集合并且记录着元素之间一种顺序关系,是最基本的数据结构之一,例如:list 和 tuple

2.表现形式

2.1 顺序表示(顺序表)

概念:用一组地址连续的存储单元依次存储线性表的数据元素,这种存储结构的线性表称为顺序表。
特点:逻辑上相邻的数据元素,物理次序也是相邻的。
只要确定好了存储线性表的起始位置,线性表中任一数据元素都可以随机存取,所以线性表的顺序存储结构是一种随机存取的储存结构,因为高级语言中的数组类型也是有随机存取的特性,所以通常我们都使用数组来描述数据结构中的顺序储存结构,用动态分配的一维数组表示线性表。

2.2链表

概念:用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的),包括数据域和指针域,数据域存数据,指针域指示其后继的信息。

结点

结点分为数据域和指针域,数据域保存着作为表元素的数据项,指针域保存同一个表里的下一个结点的标识(太绕了,通俗理解就是表明这个结点指向谁)。

  • 头结点(头结点不一定是第一个结点) 放在第一个结点之前,它的数据域一般没有意义,并且它本身也不是链表必须要带的。

  • 设立头结点的目的是什么呢?
    为了在某些时候可以更方便的对链表进行操作,有了头结点,我们在对第一个元素前插入或者删除结点的时候,它的操作与其它结点的操作就统一了。

  • 头指针 指向链表第一个结点的指针,它是链表的必备元素且无论链表是否为空,头指针都不能为空,有头结点的话,那么就是指向头结点的指针。

  • 设立头指针的目的是什么呢?
    访问链表的时候我们需要知道它的位置,才能通过它的指针域找到下一个结点的位置,也就是说知道了头指针,整个链表的元素我们都是可以访问的,所以它必须要存在,这也就是我们常说的链表的「标识」,这也就是为什么我们一般用头指针来表示链表。

单链表如图:

在这里插入图片描述

其实单链表可以想象成一列人在玩游戏,每个人都把手搭到后面那个人的肩膀上,每个人身上都有一个大口袋用来放数据,最后一个人没人可以搭就一直悬空着,第一个带头领队的就不用口袋了,它是一个头结点,是用来找到第一个有口袋的人的,也就是首元结点。

单链表基本操作原理

这样想的话就简单了,初始化的时候就是用一个人当头结点,它没有口袋,他的手是用来搭到第一个有口袋的人肩膀的,因为这个人还没来,所以它的next是Null,而取值时,通过参数i,我们就可以从首元结点开始数,数到第i个人,找到他后,就可以拿他口袋里面的东西,查找是知道口袋里面东西是什么,想找到这个东西的拥有者,也是一样从首元结点开始找。遍历下去,插入的话,比如要插入第i个位置,那么我们就先找到第i-1个人,然后让新来的手搭到第i个人身上,然后再让第i-1个人把之前放在第i个人的手挪开,放在新来的人的肩膀上,删除操作的话,例如删除第i个人,那么也是先找到第i-1个人,这里的重点是,因为链表的查询只能是从头开始找的,是不能逆回去的,所以我们需要找个变量把要删的那个人的地址先存起来,然后把第i-1个的手放到第i+1个人身上,如果我们不找个变量把那个人的地址存起来,这时候我们就没办法找到他了,因为我们用一个变量临时保存他的地址,于是我们只需要释放这个地址的空间就可以了。

题目

反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

思路

python

运用三个指针,pre、cur、lat 使用pre和cur两个指针配合工作,使得两个节点间的指向反向,依次循环
pre代表null
cur代表head(头结点)
lat代表为下一个节点

pre   cur  lat
null   1 -> 2 -> 3 -> 4 -> 5 -> null

第一次循环
cur= pre->next
将头结点变成新链表的尾节点

 pre   cur  lat
null <-1    2 -> 3 -> 4 -> 5 -> null

pre = cur,cur = lat,lat = lat.next

 	  pre  cur  lat
null <-1    2 -> 3 -> 4 -> 5 -> null

依次循环操作直到lat=None

					 pre  cur  lat
null <-1 <- 2 <- 3 <- 4    5 -> null
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if head == None:
            return []
        pre = None
        cur = head
        lat = head.next

        while lat != None:
            cur.next = pre
            pre = cur
            cur = lat
            lat = lat.next

        cur.next = pre
        return cur

在这里插入图片描述

java

首先,我们要知道最后返回的结果是链表尾节点。但先找到尾节点是很难继续实现的,因为链表没有办法高效获取前驱。要想到建立一个新的节点,之后在遍历输入的时候重新组织节点顺序,将节点挂在新节点上。所以高效的做法是在遍历链表的过程中,一个一个的把输入链表的节点放到一个新的链表头部。所以思路就是建立一个新的链表头,每次遍历输入链表的节点都把他放到新链表的头部,这样遍历完成后就获得了反转的链表。详细代码注释见下。

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode first = head;
        ListNode reverseHead = null; //建立一个新的节点用来存放结果
        while (first != null) { //遍历输入链表,开始处理每一个节点
            ListNode second = first.next; //先处理第一个节点first,所以需要一个指针来存储first的后继
            first.next = reverseHead; //将first放到新链表头节点的头部
            reverseHead = first; //移动新链表的头指针,让它始终指向新链表头部
            first = second; //继续处理原链表的节点,即之前指针存放的后继,循环往复
        }
        return reverseHead;
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值