单双链表

 

 

集合中存储的元素是有顺序的。顺序表的结构可以分为两种形式:单数据类型和多数据类型。

  单数据类型:例如np.array

  单数据类型:内存连续开辟,在内存中存储 int a = 10,20,30图例如下

  

  多数据类型:例如python中的list

  多数据类型:内存非连续开辟,在内存中如何存储 li = 10,'a',96.5,如何获取每一个数据值呢?

  

   - 顺序表的弊端:顺序表的结构需要预先知道数据大小来申请连续的存储空间,而在进行增加删除时又需要进行数据的搬迁。

   - Python中的 list 和 tuple 两种类型采用了顺序表的实现技术。

三、链表

  相对于顺序表,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。

  链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是每一个结点(数据存储单元)里存放下一个结点的信息(即地址):

  

四、单向链表:

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

    - 表中元素elem用来存放具体的数据。

    - 链接域next用来存放下一个节点的位置。

    - 变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。

  单向链表的抽象数据类型定义:

    . is_empty():链表是否为空

    . length():链表长度

    . travel():遍历整个链表

    . add(item):链表头部添加元素

    . append(item):链表尾部添加元素

    . insert(pos, item):指定位置添加元素

    . remove(item):删除节点

    . search(item):查找节点是否存在

复制代码
# 第一步:创建节点(node)
class Node(object):
    def __init__(self,item):
        # 存放新节点的值
        self.item = item
        # 新节点没有下一个链接地址
        self.next = None

# 创建链接
class Link(object):
    def __init__(self):
        # _head永远指向的第一个节点的地址
        self._head = None
        
    # 添加一个链接
    def add(self,item):
        # 创建新节点
        node = Node(item)
        # 将新节点的next地址指向 旧节点的_head指向
        node.next = self._head
        # 新节点地址指向新节点内存空间地址
        self._head = node
        
    # 获取链表值
    def travel(self):
        # 获取第一个节点指针
        cur = self._head
        
        # 判断链表next指向为空时,则为链表的最后一个节点
        while cur:
            # 打印节点item属性值
            print(cur.item)
            # 将新的节点指针赋值给cur变量
            cur = cur.next
            
    def length(self):
        # 获取第一个节点指针
        cur = self._head
        # 长度计数器
        count = 0
        
        # 判断链表next指向为空时,则为链表的最后一个节点
        while cur:
            # 打印节点item属性值
            count += 1
            # 将新的节点指针赋值给cur变量
            cur = cur.next
            
        # 打印计数器
        print("当前链表长度: ",count)
        return count
        


    # 判断链表是否为空
    def isEmpty(self):
        # 判断链表指针为None时,链表为空,返回True
        return self._head == None

    
    # 链表尾部追加元素
    def append(self,item):
        node = Node(item)

        # 判断链表是否为空
        if self.isEmpty():
            # 链表为空,添加新节点
            self._head = node
            return

        # 链表不为空,追加节点
        cur = self._head
        # 定义一个变量,保存前一个节点的地址
        pre = None

        # 判断
        while cur:
            pre = cur
            cur = cur.next

        # 最后next指针指向新加节点
        pre.next = node

    # 查询链表 查询成功返回True,否则返回False
    def search(self,item):
        find = False
        cur = self._head

        while cur:
            # 查询成功
            if cur.item == item:
                find = True
                break
            else:
                # 链表指针指向下一个链表节点
                cur = cur.next

        return find

    # 链表的插入操作
    def insert(self,pos,item):
        # 查询链表长度
        length = self.length()
        if pos <=0 or pos >length:
            print("插入位置超出范围!!!")
            return

        # pos添加的位置规定从1开始
        node = Node(item)
        cur = self._head
        pre = None
        
        # 在位置1插入
        if pos == 1:
            node.next = self._head
            self._head = node
            return 

        # for循环,使链表指针指向pos插入位置
        for i in range(1,pos):
            pre = cur
            cur = cur.next

        # 此时链表指针指向需要插入数据的位置
        # 此时把pre指向的上一个指针地址指向插入节点的地址
        pre.next = node
        # 把插入节点地址指针指向下一个节点地址
        node.next = cur

    # 删除指定位置节点
    def remove(self,item):
        # 获取第一个节点指针
        cur = self._head
        pre = None

        # 此处没有节点可以删除
        if self._head == None:
            return

        # 删除第一个节点
        if cur.item == item:
            self._head = cur.next
            return

        # 删除其他位置节点
        while cur:
            # 将新的节点指针赋值给下一个节点地址
            if cur.item == item:
                pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next


# 链表测试 # 实例化链表对象 link = Link() # 添加节点 link.add(1) link.add(2) link.add(3) # 显示链表值 link.travel() # 删除元素2 link.remove(2) link.travel() # 插入在链表位置1处插入一个节点6 link.insert(4,8) link.travel()
复制代码

五、单向循环链表

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

  基本操作和单链表基本一样,实现代码如下:

复制代码
# coding=utf-8
# 单向循环链表


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

    def __str__(self):
        return str(self.item)


class SinCycLinkedList:
    """单向循环链表"""
    def __init__(self):
        self._head = None

    def is_empty(self):
        """判断链表是否为空"""
        return self._head is None

    def length(self):
        """链表长度"""
        if self.is_empty():
            return 0
        count = 1
        cur = self._head
        while cur.next != self._head:
            # print("cur", cur.item)
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """遍历"""
        if self.is_empty():
            return

        cur = self._head
        print(cur.item)
        while cur.next != self._head:
            cur = cur.next
            print(cur.item)

    def add(self, item):
        """在头部添加一个节点"""
        node = Node(item)
        if self.is_empty():
            self._head = node
            node.next = self._head
        else:
            node.next = self._head
            cur = self._head
            while cur.next != self._head:
                cur = cur.next

            cur.next = node
            self._head = node

    def append(self, item):
        """在尾部添加一个节点"""
        node = Node(item)
        if self.is_empty():
            self._head = node
            node.next = self._head
        else:
            cur = self._head
            # print(type(cur), cur.item, cur.next)
            while cur.next != self._head:
                cur = cur.next

            # print(cur.item)
            cur.next = node
            node.next = self._head

    def insert(self, pos, item):
        """指定位置pos添加节点"""
        if pos <= 0:
            self.add(item)
        elif pos > (self.length() - 1):
            self.append(item)
        else:
            node = Node(item)
            cur = self._head
            cur_pos = 0
            while cur.next != self._head:
                if (pos - 1) == cur_pos:
                    node.next = cur.next
                    cur.next = node
                    break
                cur_pos += 1
                cur = cur.next

    def remove(self, item):
        """删除一个节点"""
        if self.is_empty():
            return

        pre = self._head
        # 删除首节点
        if pre.item == item:
            cur = pre
            while cur.next != self._head:
                cur = cur.next

            cur.next = pre.next     # 删除首节点(跳过该节点)
            self._head = pre.next   # 重新指定首节点

        # 删除其他的节点
        else:
            cur = pre
            while cur.next != self._head:
                if cur.next.item == item:
                    cur.next = cur.next.next
                cur = cur.next

    def search(self, item):
        """查找节点是否存在"""
        if self.is_empty():
            return -1

        cur_pos = 0
        cur = self._head
        if cur.item == item:
            return cur_pos

        while cur.next != self._head:
            if cur.item == item:
                return cur_pos
            cur_pos += 1
            cur = cur.next

        if cur_pos == self.length() - 1:
            return -1


if __name__ == "__main__":
    ll = SinCycLinkedList()
    ll.add(1)       # 1
    ll.add(2)       # 2 1
    # ll.travel()
    ll.append(3)    # 2 1 3
    ll.insert(2, 4) # 2 1 4 3
    ll.insert(4, 5) # 2 1 4 3 5
    ll.insert(0, 6) # 6 2 1 4 3 5
    print("length:", ll.length())        # 6
    ll.travel()                           # 6 2 1 4 3 5
    print("search(3)", ll.search(3))     # 4
    print("search(7)", ll.search(7))     # -1
    print("search(6)", ll.search(6))    # 0
    print("remove(1)")
    ll.remove(1)
    print("length:", ll.length())       # 6 2 4 3 5
    print("remove(6)")
    ll.remove(6)
    ll.travel()
复制代码

六、双向链表

  一种更复杂的链表是 "双向链表" 或 "双面链表"。每个节点有两个链接:一个指向前一个节点,当次节点为第一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。

  

  代码实现:

复制代码
# coding=utf-8
# 双向链表


class Node:
    """节点"""
    def __init__(self, item):
        self.item = item
        self.prev = None
        self.next = None


class DLinkList:
    """双向链表"""
    def __init__(self):
        self._head = None

    def is_empty(self):
        """判断链表是否为空"""
        return self._head is None

    def length(self):
        """获取链表长度"""
        if self.is_empty():
            return 0
        else:
            cur = self._head
            count = 1
            while cur.next is not None:
                count += 1
                cur = cur.next

            return count

    def travel(self):
        """遍历链表"""
        print("↓↓" * 10)
        if self.is_empty():
            print("")

        else:
            cur = self._head
            print(cur.item)
            while cur.next is not None:
                cur = cur.next
                print(cur.item)
        print("↑↑" * 10)

    def add(self, item):
        """链表头部添加节点"""
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            cur = self._head

            node.next = cur
            cur.prev = node
            self._head = node

    def append(self, item):
        """链表尾部添加节点"""
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            cur = self._head
            # 遍历找到最后一个节点
            while cur.next is not None:
                cur = cur.next

            # 在尾节点添加新的节点
            cur.next = node
            node.prev = cur

    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
            cur_pos = 0
            while cur.next is not None:
                if cur_pos == (pos - 1):
                    # 与下一个节点互相指向
                    node.next = cur.next
                    cur.next.prev = node
                    # 与上一个节点互相指向
                    cur.next = node
                    node.prev = cur
                cur_pos += 1
                cur = cur.next

    def remove(self, item):
        """删除节点"""
        if self.is_empty():
            return
        else:
            cur = self._head
            # 删除首节点
            if cur.item == item:
                self._head = cur.next
                cur.next.prev = None

            # 删除其他节点
            else:
                while cur.next is not None:
                    if cur.item == item:
                        # 删除之前:1 ←→ [2] ←→ 3
                        # 删除之后:1 ←→ 3
                        cur.prev.next = cur.next
                        cur.next.prev = cur.prev
                    cur = cur.next

                # 删除尾节点
                if cur.item == item:
                    cur.prev.next = None


    def search(self, item):
        """查找节点是否存在"""
        if self.is_empty():
            return -1
        else:
            cur = self._head
            cur_pos = 0
            while cur.next is not None:
                if cur.item == item:
                    return cur_pos

                cur_pos += 1
                cur = cur.next

            if cur_pos == (self.length() - 1):
                return -1


if __name__ == "__main__":
    ll = DLinkList()
    ll.add(1)       # 1
    ll.add(2)       # 2 1
    ll.append(3)    # 2 1 3
    ll.insert(2, 4) # 2 1 4 3
    ll.insert(4, 5) # 2 1 4 3 5
    ll.insert(0, 6) # 6 2 1 4 3 5
    print("length:", ll.length())   # 6
    ll.travel()                 # 6 2 1 4 3 5
    print("search(3)", ll.search(3))
    print("search(4)", ll.search(4))
    print("search(10)", ll.search(10))
    ll.remove(1)
    print("length:", ll.length())
    ll.travel()
    print("删除首节点 remove(6):")
    ll.remove(6)
    ll.travel()
    print("删除尾节点 remove(5):")
    ll.remove(5)
    ll.travel()

 

posted @ 2019-09-15 22:18  AnthonyWang  阅读(267)  评论(0编辑  收藏  举报