链表

链表:

链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
链表是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是在每一个结点(数据存储单元)里存放下一个结点的位置信息(即地址)。

 

单项链表:

    单向链表也叫单链表,是链表中最简单的一种形式。
    它的每个结点包含两个域,一个信息域(元素域)和一个链接域。
    这个链接指向链表中的下一个结点,而最后一个结点的链接域则指向一个空值。

链表操作:

    is_empty() 链表是否为空
    length() 链表长度
    travel() 遍历整个链表
    append(item) 链表尾部添加元素
    add(item) 链表头部添加元素
    insert(pos, item) 指定位置添加元素
    search(item) 查找结点是否存在
    remove(item) 删除结点

单个节点实现:

# 定义链表的单个结点
class Node():
    # 构造方法初始化结点
    def __init__(self, elem):
        # 初始化数据区
        self.elem = elem
        # 初始化链接区
        self.next = None

单链表的实现:

初始化
# 定义单链表
class single_linked_list():
    # 构造链表,若结点没值指向None
    def __init__(self,node=None):
        # __head代表头结点
        self.__head = node

判断非空

# 判断链表是否为空
def is_empty(self):
    # head指向None则为空
    return self.__head is None

 

cur游标代表当前结点:

# 查长度
def length(self):
    # 判断空
    if self.is_empty():
        return 0
    else:
        # 定义游标
        cur = self.__head
        # 计数
        count = 0
        # 循环
        while cur != None:
            # 让游标移动
            cur = cur.next
            count += 1
        return count
遍历,注意进循环后先打印,再移动游标
def travel(self):
    if self.is_empty():
        return
    else:
        # 游标
        cur = self.__head
        while cur != None:
            # 先打印
            print(cur.elem,end= ' ')
            cur = cur.next
        print('')

 

尾部插入:

def append(self,item):
    # 定义新结点
    node = Node(item)
    if self.is_empty():
        self.__head = node
    else:
        cur = self.__head
        # cur到最后一个结点停下
        while cur.next != None:
            # cur移动
            cur = cur.next
        # 此时,cur到达了最后一个结点
        cur.next = node

头部插入:

def add(self,item):
    # 新结点
    node = Node(item)
    if self.is_empty():
        self.__head = node
    else:
        # 这里顺序不能变
        node.next = self.__head
        self.__head = node

指定位置插入:

# pos从0开始
def insert(self,pos,item):
    # 特殊判断,友好一点
    if pos < 0:
        self.add(item)
    elif pos > (self.length()-1):
        self.append(item)
    else:
        # 新结点
        node = Node(item)
        pre = self.__head
        count = 0
        while count < (pos -1):
            # 移动游标
            pre = pre.next
            count += 1
        # 此时,pre游标指向插入位置的前一个结点
        # 下面操作顺序不能变
        node.next = pre.next
        pre.next = node

查找元素:

def search(self,item):
    if self.is_empty():
        return False
    else:
        # 定义游标
        cur = self.__head
        while cur != None:
            # 判断cur的数据是否为查找的数据item
            if cur.elem == item:
                return True
            else:
                # 游标移动
                cur = cur.next
        # 遍历完成,cur指向None
        return False

删除元素:

def remove(self,item):
    if self.is_empty():
        return
    else:
        # 定义cur游标
        cur = self.__head
        # 定义pre游标
        pre = None
        # 查找所有的位置有没有要删除的,若有则删
        while cur != None:
            # 判断cur指向的数据,是否为要删的数据
            if cur.elem == item:
                # 考虑特殊情况,恰好要删的是第一个元素
                if cur == self.__head:
                    # 头结点指向后一个结点
                    self.__head = cur.next
                else:
                    # 删除
                    pre.next = cur.next
                return
            else:
                # 移动游标,先移动pre,再移动cur
                pre = cur
                cur = cur.next

进行测试:

if __name__ == '__main__':
    sll = single_linked_list()
    print(sll.is_empty())
    print(sll.length())
    print('--------------------------')
    sll.travel()
    print('--------------------------')
    sll.append(2)
    sll.add(3)
    sll.append(5)
    sll.travel()
    print('--------------------------')
    print(sll.is_empty())
    print(sll.length())
    print('--------------------------')
    sll.insert(1,'abc')
    sll.travel()
    print(sll.search(5))
    print('--------------------------')
    sll.remove('abc')
    sll.travel()

 

链表与顺序表的对比

链表失去了顺序表随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大,但对存储空间的使用要相对灵活。

请填写链表与顺序表各种操作的时间复杂度:

操作

链表

顺序表

访问元素

O(n)

O(1)

在头部插入/删除

O(1)

O(n)

在尾部插入/删除

O(n)

O(1)

在中间插入/删除

O(n)

O(n)

 

双向链表:

    一种更复杂的链表是“双向链表”或“双面链表”。
    每个结点有两个链接:一个指向前一个结点,当此结点为第一个结点时,指向空值。
    而另一个指向下一个结点,当此结点为最后一个结点时,指向空值。
    前一个结点称为前趋结点,后一个结点称为后继结点

 

双向链表的操作:

    is_empty() 链表是否为空
    length() 链表长度
    travel() 遍历整个链表
    append(item) 链表尾部添加元素
    add(item) 链表头部添加元素
    insert(pos, item) 指定位置添加元素
    search(item) 查找结点是否存在
    remove(item) 删除结点

实现双向链表:

单个结点的实现
# 定义双向链表的结点
class Node:
    def __init__(self,elem):
        # 初始化数据区
        self.elem = elem
        self.next = None
        self.prev = None

双向链表的实现
前面几个是和单链表一样的

# 定义双向链表的结点

# 实现双链表
class double_linked_list:
    # 构造链表,若结点没值指向None
    def __init__(self,node=None):
        # __head代表头结点
        self.__head = node
    # 判断链表是否为空
    def is_empty(self):
        # head指向None则为空
        return self.__head is None
    # 查长度
    def length(self):
        # 判断空
        if self.is_empty():
            return 0
        else:
            # 定义游标
            cur = self.__head
            # 计数
            count = 0
            # 循环
            while cur != None:
                # 让游标移动
                cur = cur.next
                count += 1
            return count
    def travel(self):
        if self.is_empty():
            return
        else:
            # 游标
            cur = self.__head
            while cur != None:
                # 先打印
                print(cur.elem,end= ' ')
                cur = cur.next
            print('')

尾查,处理前驱:
def append(self,item):
    node = Node(item)
    if self.is_empty():
        self.__head = node
    else:
        # 移动游标
        cur = self.__head
        while cur.next != None:
            cur = cur.next
        # 此时,cur指向最后一个结点
        cur.next = node
        # 处理前驱结点
        node.prev = cur

 

头插:

def add(self,item):
    node = Node(item)
    if self.is_empty():
        self.__head = node
    else:
        # 新结点指向原第一个结点
        node.next = self.__head
        self.__head = node
        # 处理原第一个结点的前驱
        node.next.prev = node

指定位置插入:

def insert(self,pos,item):
    if pos < 0:
        self.add(item)
    elif pos > (self.length() -1):
        self.append(item)
    else:
        # 创建结点
        node = Node(item)
        # 游标
        cur = self.__head
        count = 0
        # 因为cur停在后一个位置,所以看图吧
        while count < pos:
            cur = cur.next
            count += 1
        # 此时,cur停在后一个结点
        node.next = cur
        node.prev = cur.prev
        cur.prev.next = node
        cur.prev = node

删除元素:

def remove(self,item):
    if self.is_empty():
        return
    else:
        cur = self.__head
        while cur != None:
            # 对比是否为要删的元素
            if cur.elem == item:
                # 考虑特殊情况,若找到的结点,恰好为第一个结点
                if cur == self.__head:
                    # 头直接指向后一个结点
                    self.__head = cur.next
                    # 考虑链表只有一个结点的情况下,None.prev会出问题
                    if cur.next:
                        cur.next.prev = None
                else:
                    # 当前结点的前一个指向后一个
                    cur.prev.next = cur.next
                    # 考虑后面没有结点的情况
                    if cur.next:
                        cur.next.prev = cur.prev
                return
            else:
                cur = cur.next

 

单向循环链表:

单链表的一个变形是单向循环链表。
链表中最后一个结点的next域不再为None,而是指向链表的头结点。

单个结点实现:与前面的单向链表一样

单向循环链表的实现:

定义单向循环链表:

class single_loop_list:
    def __init__(self,node=None):
        self.__head = node
        # 特殊处理回环
        if node:
            node.next = node

 

求长:

def length(self):
    if self.is_empty():
        return 0
    else:
        cur = self.__head
        # count从1开始
        count = 1
        while cur.next != self.__head:
            # 移动
            cur = cur.next
            count += 1
        return count

遍历:


def travel(self):
if self.is_empty():
return
else:
cur = self.__head
while cur.next != self.__head:
# 先打印再移动游标
print(cur.elem,end=' ')
cur = cur.next
# 退出循环,cur指向了尾结点
print(cur.elem,end=' ')
print('')

尾插:

def append(self,item):
    node = Node(item)
    if self.is_empty():
        self.__head = node
        # 处理回环
        node.next = node
    else:
        # 游标走到最后
        cur = self.__head
        while cur.next != self.__head:
            cur = cur.next
        # cur此时在最后一个位置
        # 新结点指向头
        node.next = self.__head
        # 原最后结点,指向新结点
        cur.next = node

头插:吃处理回环

def add(self,item):
    # 结点
    node = Node(item)
    if self.is_empty():
        self.__head = node
        node.next = node
    else:
        cur =self.__head
        # 移动游标
        while cur.next != self.__head:
            cur = cur.next
        # cur停留在最后的位置
        node.next = self.__head
        self.__head = node
        # 形成回环
        cur.next = node

指定位置插入:与单链表一样

查找元素:注意别丢下最后一个

def search(self,item):
    if self.is_empty():
        return False
    else:
        # 定义游标
        cur = self.__head
        while cur.next != self.__head:
            # 判断cur的数据是否为查找的数据item
            if cur.elem == item:
                return True
            else:
                # 游标移动
                cur = cur.next
        # 处理最后一个结点
        if cur.elem == item:
            return True
        # 遍历完成,cur指向None
        return False

删除元素:

def remove(self, item):
    if self.is_empty():
        return
    else:
        cur = self.__head
        pre = None
        # 循环条件
        while cur.next != self.__head:
            # 判断cur的数据是否为要删的数据
            if cur.elem == item:
                if cur == self.__head:
                    # 考虑删的恰好是第一个结点
                    # 考虑回环,还需要一个游标拿到尾结点位置
                    # 这里直接将rear移动到最后即可
                    rear = self.__head
                    while rear.next != self.__head:
                        rear = rear.next
                    # 此时rear指向最后一个结点
                    self.__head = cur.next
                    # 回环
                    rear.next = self.__head
                else:
                    # 其他结点
                    pre.next = cur.next
                return
            else:
                # 移动游标
                pre = cur
                cur = cur.next
        # 退出循环时,cur指向最后一个结点
        if cur.elem == item:
            # 考虑只有一个结点
            if cur == self.__head:
                self.__head = None
            else:
                pre.next = cur.next

 

posted @ 2019-04-26 16:58  哄哄的锤石真菜  阅读(267)  评论(0编辑  收藏  举报