31.1-习题单双向链表实现

人生需要三种姿态
对过去,要淡;
对现在,要惜;
对未来,要信。

如果担心现在才开始学某样东西
年纪已经太大的话
不妨这样想 :就算因此放弃不学,年纪还是照样会变大的。

人生,任何时候开始都不晚,只要行动就有机会!

难点章节
程序员基本功: 写一大段代码基本不会出错,最怕的是逻辑混乱,逻辑混乱写什么都是错的;

总结:

  1. for循环在python中是在知道有限次数的情况下使用的;
  2. 锻炼自己的应该是 逻辑思维;分析代码的能力;思路不清晰,说明你不得法;

链表是每个程序员都应该知道的基本数据结构!
可分为两类:链表类(容器),元素类(里面提交合法的值)

1. 链表LinkedList

链表:是一种以线性顺序存储的数据结构,但并不要求按顺序存储。它由节点组成,每个节点除了储存自身数据外,还包含一个指向下一个节点的引用(或指针)。

打个比方:列表就好像火车,每一节车厢连在一起,如果你知道车头在哪里,大致就也能知道第8节车厢在哪。

而链表,就像是去往同个目的地的车队,有很多辆车,大家排着队行驶。虽是一个整体,但队伍的顺序是可以很容易调整的。

单链表

两个特例:(头和尾)我们会有一个 head 引用指向链表的开头,而链表的结尾,下一个节点则指向空值 None。

除了上图演示的单向链表外,还存在双向链表(每个节点还增加一个指向前一个节点的引用)和循环链表(最后一个节点的下一个节点会指向第一个节点)

1.1 单向链表

链表中最简单的形式
每个节点包含两个域,一个元素域,一个链接域
链接指向链表中的下一个节点;最后一个节点的链接域指向一个空值
head 保存首地址;item 存储元素(数据);next 指向下一个节点地址

链表 VS 序列
序列:随机读取,使用下标
链表:增加指针域,空间开销偏大,使用更加灵活,如插入

1.2 双向链表

比单向链表复杂
每个节点有两个链接
一个指向前一个节点,当此节点为第一个节点时,指向空值

另一个链接指向下一个节点,当此节点为最后一个节点时,指向空值
head 保存首地址,item 存储数据,next 指向下一节点地址,prev 指向上一结点地址

常用操作方法
is_empty() 链表是否为空
length() 链表长度
items() 获取链表数据迭代器
add(item) 链表头部添加元素
append(item) 链表尾部添加元素
insert(pos, item) 指定位置添加元素
remove(item) 删除节点
find(item) 查找节点是否存在
链表的优点和缺点
  1. 链表相较顺序存储列表,最大的好处就是很容易往序列中添加和删除元素,单看插入和删除操作,最优可达到O(1)的复杂度
  2. 不需要连续的存储空间,且不需要预先知道数据集的大小。
  3. 链表没有顺序表随机读取的优点,同时增加了节点的指针域,增大了空间开销,但是对内存的使用相对更灵活。
操作 链表 顺序表
访问元素 O(n) O(1)
头部插入/删除 O(1) O(n)
尾部插入/删除 O(n) O(1)

练习:1.用面向独享实现LinkedList链表

单向链表实现append、iternodes方法;
双向链表实现append、pop、insert、remove、iternodes方法;

单向链表

class Node:
    def __init__(self,item,next=None):
        self.item = item  # 实例记录 数据部分;
        self.next = next  # 下一趟是谁? 有:没有:None
        
    def __repr__(self): # 观察数据;
        return '< {} -->{}>'.format(self.item,self.next.item if self.next else 'None')
    
class LinkedList:  # 链表
    def __init__(self):
        self.head = None  # 头部结点;
        self.tail = None  # 尾部结点;
        self.items = []
        
    def append(self,item):
        node = Node(item) # 创建结点对象
        
        if self.head is None: # 空链表;
            self.head = node
            #self.tail = node
        else:                 #非空链表;
            self.tail.next = node
            #self.tail = node
        self.tail = node
        return self

    def iternodes(self):
        current = self.head
        while current:
            yield current
            current = current.next
        
ll = LinkedList()
ll.append(1)
ll.append(2).append(3)

for x in ll.iternodes():
    print(x)
#------------------------------------------------
< 1 -->2>
< 2 -->3>
< 3 -->None>


class Node:
    def __init__(self,item,next=None):
        self.item = item  # 实例记录 数据部分;
        self.next = next  # 下一趟是谁? 有:没有:None
        
    def __repr__(self): # 观察数据;
        return '< {} -->{}>'.format(self.item,self.next.item if self.next else 'None')
    
class LinkedList:  # 链表
    def __init__(self):
        self.head = None  # 头部结点;
        self.tail = None  # 尾部结点;
        self.items = []
        
    def append(self,item):
        node = Node(item) # 创建结点对象
        
        if self.head is None: # 空链表;
            self.head = node
            #self.tail = node
        else:                 #非空链表;
            self.tail.next = node
            #self.tail = node
        self.tail = node
        self.items.append(node)
        return self
    
    def get(self,index):
        return self.items[index]

    def iternodes(self):
#         current = self.head
#         while current:
#             yield current
#             current = current.next
        #return iter(self.items)
        yield from self.items
        
ll = LinkedList()
ll.append(1)
ll.append(2).append(3)
print(ll)

for x in ll.iternodes():
    print(x)
#--------------------------------------------------
<__main__.LinkedList object at 0x000001A0115E4128>
< 1 -->2>
< 2 -->3>
< 3 -->None>

双向链表
双向链表实现 append,pop,insert,remove,iternodes 方法;

class Node:  # 结点对象;
    def __init__(self,item,prev=None,next=None):
        self.item = item  # 实例记录 数据部分;
        self.next = next  # 下一趟是谁? 有:没有:None
        self.prev = prev
        
    def __repr__(self): # 观察数据;
        return '< {} -->{}>'.format(
            self.item,
            self.next.item if self.next else 'None',
            self.next.item if self.next else 'None')

class LinkedList:  # 链表
    def __init__(self):
        self.head = None  # 头部结点;
        self.tail = None  # 尾部结点;
        self.items = []
        
    def append(self,item):
        node = Node(item) # 创建结点对象
        
        if self.head is None: # 空链表;
            self.head = node
            #self.tail = node
        else:                 #非空链表;
            node.prev = self.tail
            self.tail.next = node
            #self.tail = node
        self.tail = node  # 更新尾部结点;
        self.items.append(node)
        return self
    
    def insert(self,index,value):
        if index < 0:
            raise IndexError('Negative index erro {}'.format(index))
            
        for i,node in enumerate(self.iternodes()):
            if i == index:
                current = node
                break
        else:
            self.append(value)
            return 
        # 找到了插入点和元素;
        node = Node(value)   # 待加入结点对象;
        prev = current.prev
        next = current.next
        
        if index == 0:
#             node.next = current
#             current.prev = node
            self.head = node
        else:
#             node.next = current
#             current.prev = node
            node.prev = prev
            prev.next = node
        node.next = current
        current.prev = node           
    def pop(self):  # 尾部移除
        if self.tail is None: # 0元素
            raise Exception('Empty')
            
        node = self.tail
        item = node,item
        prev = node.prev
        
        if prev is None:    # 一个元素;
            self.head = None
            self.tail = None
        else:               # 2个元素,移除元素,只剩最后一个
            prev.next = None
            self.tail = prev
        
    def remove(self,index):
        if index < 0:
            raise IndexError('Negative index erro {}'.format(index))
        if self.head is None: # 0元素
            raise Exception('Empty')
            
        current = None
        for i,node in enumerate(self.iternodes()):
            if i == index:
                current = node
                break
        else:
            raise IndexError('wrong index') 
        # 找到了要移除的结点; current = node ;
        prev = current.prev
        next = current.next
        
        # 分4种情况; just one;
        if prev is None and next is None:
            self.head = None
            self.tail = None
        elif prev is None: #不是一个元素,且头部移除
            self.head = next
            self.tail = None
        elif next is None: #不是一个元素,且尾部移除
            self.tail = prev
            prev.next = None
        else: # 不是一个元素,且中间移除
            prev.next = next
            next.prev = prev
        
    def iternodes(self,reverse=False):
        current = self.tail if reverse else self.head
        while current:
            yield current
            current = current.next if not reverse else current.prev
        
ll = LinkedList()
ll.append(1)
ll.append(2).append(3)

ll.insert(0,0)
ll.insert(0,'abc')
ll.insert(1000,'end')

#print(ll.pop())
for x in ll.iternodes():
    print(x)
#------------------------------
< abc -->0>
< 0 -->1>
< 1 -->2>
< 2 -->3>
< 3 -->end>
< end -->None>

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

推荐阅读更多精彩内容

  • 摘自《维基百科》 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储...
    ChinaChong阅读 1,694评论 0 52
  • 基本概念 链表的含义: 链表是一种用于存储数据集合的数据结构,具有以下属性 相邻元素之间通过指针相连 最后一个元素...
    古剑诛仙阅读 1,006评论 0 3
  • Go实现双向链表 本文介绍什么是链表,常见的链表有哪些,然后介绍链表这种数据结构会在哪些地方可以用到,以及 Red...
    link1st阅读 603评论 0 1
  • 与RDBMS的优势: 1、计算机硬盘发展的趋势:寻址地址的提升远远不敌传输速率的提升 2、RDBMS传统B树结构小...
    文艺复兴young阅读 223评论 0 0
  • 《你就是孩子最好的玩具》,听了以后恍然大悟,我们曾走过这么的误区,下边这些我都做过,当你看过以后,有没有觉得自己很...
    静待花开jl阅读 115评论 0 0