Bootstrap

【数据结构】双向链表、单向循环链表、双向循环链表、栈、链栈

目录

一、双向链表

定义类和封装函数以及测试样例如下:

注意事项:

二、循环链表

单循环列表的类和函数封装如下:

注意事项: 

三、双向循环链表

结点类和双循环链表的定义部分

函数封装之判空和尾插

双循环链表遍历

双循环链表尾删

完整测试以及结果:

四、栈

顺序栈

顺序栈本质以及组成

顺序栈的操作

链栈


一、双向链表

对于单向链表而言。只能通过头节点或者第一个节点出发,单向的访问后继节点,每个节点只能记录其后继节点的信息(位置),不能向前遍历。

所以引入双向链表,双向链表可以保持单向链表特点的基础上,让每个节点,既能向后访问后继节点,也可以向前访问前驱节点。

相较于单向链表,我们更多的是在每个结点上加入了一个前驱链接域

定义类和封装函数以及测试样例如下:

class Node(object):
    def __init__(self,data):
        self.next = None
        self.prior = None
        self.data = data

class DoubleLinklist(object):
    def __init__(self):
        self.head = None
        self.size = 0

    def is_empty(self):
        return self.size == 0

    def add_head(self,value):
        node=Node(value)
        if self.is_empty():
            self.head = node
            self.size+=1
        else:
            node.next = self.head
            self.head.prior = node
            self.head = node
            self.size += 1

    def show_me(self):
        if self.is_empty():
            print('空表查看不了')
        else:
            q = self.head
            while q :
                print(q.data,end=' ')
                q = q.next

    def add_anywhere(self,location,value):
        if location < 1 or location > self.size+1:
            print('插入失败')
        else:
            node = Node(value)
            if location == 1:
                self.add_head(value)
            else:
                q = self.head
                i = 1
                while i< location-1:
                    q = q.next
                    i += 1
                if q.next is None:
                    q.next = node
                    node.prior = q
                else:
                    node.next = q.next
                    node.prior = q
                    q.next.prior = node
                    q.next = node
                self.size+=1

    def del_anywhere(self,location):
        if self.is_empty() or location < 1 or location > self.size:
            print('删除失败')
        else:
            if location == 1:
                self.head = self.head.next
                self.head.prior = None
            else:
                q=self.head
                i =1
                while i < location :
                    q = q.next
                    i += 1
                if  q.next :
                    q.prior.next = q.next
                    q.next.prior = q.prior
                else:
                    q.prior.next = None
            self.size -=1

    def find_node(self,value):
        if self.is_empty():
            print('查找失败')
        else:
            q = self.head
            while q:
                if q.data == value:
                    return True
                q = q.next
            return False






if __name__ == '__main__':
    new_l=DoubleLinklist()
    print('头插')
    new_l.add_head(50)
    new_l.add_head(40)
    new_l.add_head(30)
    new_l.add_head(20)
    new_l.add_head(10)
    new_l.show_me()
    print()

    print('任意位置插入')
    new_l.add_anywhere(1,666)
    new_l.add_anywhere(7,666)
    new_l.add_anywhere(3,666)
    new_l.show_me()
    print()

    print('任意位置删除')
    new_l.del_anywhere(8)
    new_l.del_anywhere(3)
    new_l.del_anywhere(1)
    new_l.show_me()
    print()

    print('找是否存在值30')
    print(new_l.find_node(30))
    print()

结果如下:

注意事项:

对链表的删除和插入操作我们均要考虑空表、末尾元素、单个元素情况;双循环链表的插入操作 :                       node.next = q.next
                    node.prior = q
                    q.next.prior = node
                    q.next = node

这四条语句除了第一条的位置不能变动以外(防止丢失结点),后面的操作前后顺序没有强制要求。


二、循环链表

循环链表:就是首尾相连的链表,通过任意一个节点,都能将整个链表遍历一遍

单循环列表的类和函数封装如下:


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

class CirculateLinkList(object):
    def __init__(self):
        self.head = None
        self.size = 0

    def is_empty(self):
        return self.size == 0

    def add_tail(self,value):
        node = Node(value)
        if self.is_empty():
            self.head = node
            node.next = node
        else:
            q = self.head
            i = 1
            while i < self.size:
                q = q.next
                i += 1
            q.next = node
            node.next = self.head
        self.size += 1

    def show_me(self):
        if self.is_empty():
            print('空表')
        elif self.size == 1 :
            print(self.head.data)
        else:
            q = self.head
            i = 1
            while i < self.size+1:  #q要定位到第一个结点才能遍历完
                print(q.data,end=' ')
                q=q.next
                i += 1

    def del_tail(self):
        if self.is_empty():
            print('删除失败')
        elif self.size == 1 :
            self.head = None
            self.size -=1
        else:
            q = self.head
            i = 1
            while i < self.size-1 :
                q = q.next
                i+=1
            q.next = self.head
            self.size -= 1

if __name__ == '__main__':
    new_l=CirculateLinkList()
    print('尾插')
    new_l.add_tail(30)
    new_l.add_tail(20)
    new_l.add_tail(10)
    new_l.show_me()
    print()

    print('尾删')
    new_l.del_tail()
    new_l.del_tail()
    new_l.show_me()
    print()



结果:

注意事项: 

基本注意事项不再赘述,这里有个格外要注意的点:


    def show_me(self):
        if self.is_empty():
            print('空表')
        elif self.size == 1 :
            print(self.head.data)
        else:
            q = self.head
            i = 1
            while i < self.size+1:  #q要定位到第一个结点才能遍历完
                print(q.data,end=' ')
                q=q.next
                i += 1

while循环要多循环一次,使得q指向第一个结点才能遍历完整


三、双向循环链表

双循环链表同样需要考虑几个点,如何创建,如何增删改查,由于是双向的,那么可以不用像单向的删除操作中一定要找到删除元素前一个位置,可以直接定位到要删除的位置,只需要把前驱后继都重新分配好即可。

结点类和双循环链表的定义部分

class Node(object):
    def __init__(self,data):
        self.data=data
        self.next=None
        self.prior=None

class DoubleCirculateLinkList(object):
    def __init__(self):
        self.head=None
        self.size=0

函数封装之判空和尾插

 注意:尾插部分要注意分空表和单元素情况

    def is_empty(self):
        return self.size == 0

    def add_tail(self,value):
        node=Node(value)
        if self.is_empty():
            self.head=node
            node.next=node
            node.prior=node
        elif self.size == 1:
            self.head.next=node
            self.head.prior=node
            node.next=self.head
            node.prior=self.head
        else:
            q=self.head
            while True:
                q=q.next
                if q.next==self.head:
                    break
            node.next=self.head
            node.prior=q
            q.next=node
            self.head.prior=node
        self.size+=1

这里的常规尾插我用到的遍历循环是while True:内部增加一个判断退出的条件来获得末尾结点q

情况全分析完毕整体判断外size+=1即可

双循环链表遍历

遍历涉及到打印,我们用一个变量q来记录,常规情况下要遍历到最后一个结点,但这还不够,要执行的下去循环内的打印语句才行,所以要留意。

 def show_me(self):
        if self.is_empty():
            print('空表')
        else:
            q=self.head
            while True:
                print(q.data,end=' ')
                q=q.next
                if q ==self.head:
                    break

双循环链表尾删

首先,空表无法删除,单元素删除直接head==None,常规情况可直接遍历到最后一个结点(由于是双向的链表所以不用找倒数第二个结点了),然后将该结点的前驱结点next指向head,head指向的结点的前驱再指向回来即可删除。

    def del_tail(self):
        if self.is_empty():
            print('空表')
        elif self.size == 1:
            self.head = None
        else:
            q=self.head
            while True:
                q=q.next
                if q.next==self.head:
                    break
            q.prior.next=self.head
            self.head.prior=q.prior
        self.size-=1

完整测试以及结果:

class Node(object):
    def __init__(self,data):
        self.data=data
        self.next=None
        self.prior=None

class DoubleCirculateLinkList(object):
    def __init__(self):
        self.head=None
        self.size=0

    def is_empty(self):
        return self.size == 0

    def add_tail(self,value):
        node=Node(value)
        if self.is_empty():
            self.head=node
            node.next=node
            node.prior=node
        elif self.size == 1:
            self.head.next=node
            self.head.prior=node
            node.next=self.head
            node.prior=self.head
        else:
            q=self.head
            while True:
                q=q.next
                if q.next==self.head:
                    break
            node.next=self.head
            node.prior=q
            q.next=node
            self.head.prior=node
        self.size+=1

    def show_me(self):
        if self.is_empty():
            print('空表')
        else:
            q=self.head
            while True:
                print(q.data,end=' ')
                q=q.next
                if q ==self.head:
                    break

    def del_tail(self):
        if self.is_empty():
            print('空表')
        elif self.size == 1:
            self.head = None
        else:
            q=self.head
            while True:
                q=q.next
                if q.next==self.head:
                    break
            q.prior.next=self.head
            self.head.prior=q.prior
        self.size-=1

if __name__ == '__main__':
    new_l=DoubleCirculateLinkList()
    print('尾插')
    new_l.add_tail(10)
    new_l.add_tail(20)
    new_l.add_tail(30)
    new_l.add_tail(40)
    new_l.add_tail(50)
    new_l.show_me()
    print()

    print('尾删')
    new_l.del_tail()
    new_l.del_tail()
    new_l.show_me()
    print()


四、栈

顺序栈

顺序存储的栈即是顺序栈

顺序栈本质以及组成

本质上:顺序栈是一个只允许在栈顶进行插入和删除操作的顺序表,遵循LIFO

需要使用一个容器存储一个栈,例如列表

顺序栈的操作

这里直接使用内置函数去对栈封装

class Stack(object):
    def __init__(self):
        self.data = []

    def is_empty(self):
        return self.data == []

    def push(self,value):
        self.data.insert(0,value)

    def pop(self):
        self.data.pop(0)

    def show(self):
        for i in self.data:
            print(i,end=' ')
        print()

    def get_top_value(self):
        return self.data[0]

    def get_size(self):
        return len(self.data)

链栈

既然顺序栈就是对栈顶元素增删的特殊的顺序表,那么链栈就是对栈顶元素增删的特殊的单向链表

这里我的pop不仅实现了删除,而且还增加了额外的返回值

代码如下:

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

class LinkStack(object):
    def __init__(self):
        self.size=0
        self.head=None

    def is_empty(self):
        return self.size==0

    def push(self,value):
        node=Node(value)
        node.next=self.head
        self.head=node
        self.size+=1

    def pop(self):
        if self.is_empty():
            print('空栈')
        else:
            q=self.head.data
            self.head=self.head.next
            self.size-=1
            return q

    def show(self):
        if self.is_empty():
            print('空栈')
        else:
            q=self.head
            while q:
                print(q.data,end=' ')
                q=q.next

    def get_top_value(self):
        if self.is_empty():
            return None
        else:
            return self.head.data

    def get_size(self):
        return self.size

未完待续(持续跟新中)🏆

;