链表之单向链表

链表之单向链表

1、结点

结点是链表中一个重要且基本的组成部分,结点的形式是,第一个存储区存储结点元素数据,第二个存储区存储下一个结点的地址。以下采用python定义一个LNode类:

class LNode:
    '''
    这是自我定义的链表,包含了链表的基本结构和方法
    '''
    def __init__(self,elem,next_=None):
        '''
        一个self为一个结点
        第一个元素elem为结点的数值,第二个元素为下一个结点的位置
        :param elem:
        :param next_:
        '''
        self.elem = elem
        self.next = next_

2、单向链表

2.1 定义链表

链表是一个一个结点相连组成的结构,为了避免过于抽象,这里先定义一个单向链表:

class List_Single:
    '''
        这是自我定义单向链表,包含了链表的基本结构和方法
        '''
    def __init__(self):
        self._head = None
    def is_empty(self):
        return self._head is None

2.2列表方法

链表也需要像python的其它官方结构一样,具有可以在头尾端插入数据以及删除数据的功能

1、头部增删结点

  • 头部删除结点
 def pop(self):
        '''
        功能:删去链表头部结点,并显示该结点的数据信息
        实现思想:
        首先判断链表本身是否有结点【判断是否为空】,若空则返回异常
        其次:将表头结点的信息用一个变量保存
        最后将指向一个表头结点的self._head地址信息改为该表头结点的指向地址即可
        :return:
        '''
        if self.is_empty():
            raise LinkedListUnderflow('in pop')
        e = self._head.elem#将表头结点的值保存起来
        self._head = self._head.next#将指针移向下一个结点
        return e # 返回删除的表头数据

  • 头部增加结点
    def prepend(self,elem):
        '''
        在链表的头部加入一个结点:
        实现思想:
        由于链表只需要找到第一个元素的位置,
        所以只需要将self._head指向新增的结点,而结点指向增加元素前的头部
        传入结点的值
        :param elem:
        :return:
        '''
        self._head = LNode(elem,self._head)

   

2 尾部增删结点

  • 尾部删除结点
    在链表的尾部增删数据和在头部有所不同,在尾部删除数据,需要找到最后一个数据的前一个结点,然后将前一结点的第二个元素指针设置为空,这样链表就可以实现删除尾端最后一个数据,代码示例:
    def pop_last(self):
        '''
        函数功能:将链表的最后一个结点删除并且返回结点的值
        功能实现:
        第一步:与pop类似,要确认链表确实有结点,
        Note:如果第一个结点就是最后一个结点,加上一个判断条件会很大程度上减少复杂度

        第二步:采用append类似的方法,遍历结点,然后将他的上一个结点指针指向None【逻辑删除】
        :return:
        '''
        if self.is_empty():#如果是空表,引发异常
            raise LinkedListUnderflow('in pop_last')
        p = self._head#遍历指针
        if p.next is None:#表中只有一个元素
            e = self._head.elem#保存第一个元素的值
            self._head = None#将表变为空表
            return e #返回元素的值
        #开始遍历操作
        while p.next.next is not None:
            #即p为倒数第二个结点,
            # 那么p.next就是最后一个结点,所以p.next.next为None
            p = p.next#p变为p的下一个结点
        #找到了p为最后一个结点
        e = p.next.elem
        p.next = None#将最后一个结点删除,意即倒数第二个结点p的下一个指向为None
        return e
  • 尾部增加结点
    在尾端增加数据,也同尾端删除数据一样,需要用到遍历指针p,故复杂度也是O(n)级别,代码示例如下:
    def append(self,elem):
        '''
        功能:在链表尾部加上一个元素
        实现思想:
        需要foreach(遍历)找到self._head.next = None的元素(如果链表为空将会简单很多)
        然后将self._head.next = 要插入的结点地址
        :param elem:
        :return:
        '''
        if self.is_empty():
            self._head = LNode(elem)#直接将表头指向新加入的元素
            return
        p = self._head#用一个中间变量来当作遍历指针
        while p.next is not None:#如果结点指向的下一地址不为空
            p = p.next#那么遍历指针指向下一个结点
        p.next = LNode(elem)#找到最后一个结点后,
        # 将遍历指针代表的结点的next地址指向新增的结点

3 查找功能

  • 条件匹配
    第一个方法是设计用于在链表中查找是否有满足一个方法【在这里即设为pred方法】的结点,如果有则返回数据。如果有多个则返回第一个
    def find(self,pred):
        '''
        找出满足pred方法的元素,且该pred方法还有一个参数
        实现方法:同样地,采用链表方式
        :param pred:
        :return:
        '''
        p = self._head
        while p is not None:#p不为空
            if pred(p.elem):#如果满足方法pred的条件
                return p.elem#则返回结点的数据
            p = p.next#将p指向p的下一个元素

4 打印所有结点元素

  • 定义
    为了使得链表可视化,设计了这个方法
    ···
    def printall(self):
    p = self._head#将遍历指针p,p指向链表头
    while p is not None:#当链表不为空
    print(p.elem,end = '')
    if p.next is not None:#当p不是最后一个元素
    print(', ',end='')#打印一个',',使其格式化

          p = p.next
      print('')#只是换行
    

···

  • 打印示例
    如果要调用printall方法来打印,则直接调用即可,下面是调用示例
mlist1 = List_Single()#示例化一个链表结构
for i in range(10):
    mlist1.prepend(i)#往链表的前端加入结点

for i in range(11,20):
    mlist1.append(i)#往链表的尾端加入结点

mlist1.printall()#输出9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 11, 12, 13, 14, 15, 16, 17, 18, 19

3 总结

今天关于单向链表的基础就到这里结束,可以看出如果需要在链表的尾端增删元素,复杂度都是O(n),那有没有更为高效的算法呢?我们明天见!

4 联系方式

如果您对本文有意见或者建议,欢迎通过邮箱与我联系:psywency@foxmail.com
比心心​
:heart:​

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 一、OC基本数据类型 计算一下他们的取值范围: 以int 为例:int所在4个字节 1Btye = 8bit。 共...
    蓝童鞋阅读 288评论 0 0
  • 参考文章:python中os模块函数方法详解最全最新 - 阿波罗Apollo - 博客园 pyth...
    可乐W阅读 209评论 0 0
  • 如何正确认识选款以及测款 让店铺赢在起跑...
    雨中的悲伤01阅读 258评论 0 0
  • 今天到此刻为止,认定今天自己简直了。 1.没有设计好交流方法 2.没有认真的做好计划 3.没有经过大脑就讲话 4....
    灵子_4072阅读 101评论 0 1
  • 女神节的长沙好冷,今天安全的老师叫我们为和尚班,但他其实不知道这里还有个来自华为的那个娘炮以及饲养员班主任。昨天做...
    顶着风儿嘘嘘阅读 167评论 0 0