数据结构——线性结构(链表)

  链表定义:链表是由一系列节点组成的元素结合。每个节点包含两个部分,数据域item指向下一个节点的指针next。通过节点之间的相互连接,最终串联成一个链表。

一、单链表

  

1、节点定义

class Node:
    def __init__(self, item):
        self.item = item
        self.next = None

# 模拟链表
a = Node(1)
b = Node(2)
c = Node(3)
a.next = b
b.next = c

print(a.next.next.item)   # 输出:3

2、建立链表

(1)头插法

  头插法是在头结点这边插入。

  

(2)尾插法

  不光要知道头还需要知道尾在哪。从尾节点插入。

  

(3)代码实现 

class Node:
    def __init__(self, item):
        self.item = item    # 存放数据
        self.next = None   # 指针,指向下一个节点


def create_linklist_head(li):
    """头插法创建链表"""
    head = Node(li[0])    # 头节点
    for element in li[1:]:   # 从第二个到最后一个遍历列表
        node = Node(element)    # 实例化为一个链表节点
        node.next = head     # 设置实例的next属性指向链表头节点
        head = node      # 将新加入链表节点设置为头节点
    return head      # 要遍历链表需要从头往回找


def create_linklist_tail(li):
    """尾插法创建链表"""
    head = Node(li[0])   # 创建头节点对象
    tail = head          # 尾节点也是头节点
    for element in li[1:]:    # 从第二个到最后一个遍历列表
        node = Node(element)    # 创建一个新链表节点
        tail.next = node    # 设置实例next属性指向链表尾节点
        tail = node      # 将新加入链表的节点设置为尾节点
    return head      # 返回头节点,可以从头往回找


def print_linklist(lk):
    """打印链表"""
    while lk:   # 只要lk存在
        print(lk.item, end=',')    # 打印链表值
        lk = lk.next      # 到最后一个节点的时候,lk.next属性为空退出循环


lk = create_linklist_head([1, 2, 3])
print(lk)
print_linklist(lk)
"""
<__main__.Node object at 0x10402de48>
3,2,1,
"""

lk2 = create_linklist_tail([1, 3, 6, 8, 9])
print_linklist(lk2)
"""
3,2,1,1,3,6,8,9,
"""

3、链表的遍历

  

4、链表节点的插入和删除(视频缺,需要补)

 

二、双链表

  双链表的每个节点有两个指针:一个指向后一个节点,另一个指向前一个节点。

  

1、节点定义

class Node(object):
    def __init__(self, item):
        self.item = item    # 数据
        self.next = None   # 指针,指向后一个节点
        self.prior = None   # 指针,指向前一个节点

2、双链表节点插入

#插入
p.next = curNode.next
curNode.next.prior = p 
p.prior = curNode
curNode.next = p

  代码过程图示如下:

(1)p.next = curNode.next   让p.next指针指向curNode下一个节点

  

(2)curNode.next.prior = p  让curNode下一个节点的prior指针指向p

  

(3)p.prior = curNode   让p的prior指针指向curNode

  

(4)curNode.next = p  让curNode的next指针指向p

  

3、双链表节点的删除

#删除
p = curNode.next
curNode.next = p.next
p.next.prior = curNode
del p

  代码过程图示如下:

(1)p = curNode.next  指定要删除的节点是curNode的next指针指向的节点

  

(2)curNode.next = p.next  修改curNode的next指针指向要删除节点的next指针指向的节点

  

(3)p.next.prior = curNode  修改p的next指针指向的节点的prior指针,将指针指向curNode

  

(4)del p    删除p

三、链表总结

1、顺序表(列表)与 链表复杂度对比分析

  按元素值查找时:都是挨个查看,时间复杂度都为O(n)

  按下标查找时:顺序表更快,直接插入到对位位置。链表则需要从头开始数。链表时间复杂度是O(n),顺序表时间复杂度是O(1)。

  在某元素后插入:这种情况顺序表是O(n),插入后,后面的元素都需要往后挪。链表则是O(1)。

  删除某元素:这种情况顺序表是O(n),删除后,后面的元素都需要往前挪。链表则是O(1)。

2、链表和顺序表对比总结

  链表在插入和删除操作上明显快于顺序表

  链表的内存可以更灵活的分配。java等的数组一开始申请的空间如果满了是没有办法解决的,python的列表在一开始申请的空间不足时,也是通过重新申请新的空间,将原来内存空间的内容拷贝进去。

    可以尝试利用链表重新实现栈和队列,使用栈实现队列就不用考虑队满的问题,也不用设计为环形。

  链表这种链式存储的数据结构对树和图的结构有很大的启发性。

 

 

 

 

 

  

 

 

posted @ 2018-09-24 12:35  休耕  阅读(1867)  评论(2编辑  收藏  举报