024.【链表算法】

1. 创建单向链表

例如,有“学生”这样一个链表,链表中需要包括学生的姓名、性别、学号等一些基本信息。创建这样的一个链表,链表里面包括多个学生的信息。

在这里插入图片描述
可以看出,“学生一”的尾结点“next”指向了下一个“学生二”的头结点学号“02”,这就是链表的特性,即上一个信息的尾结点next会指向下一个信息的头结点的内存地址。由于每个结点都包含了可以链接起来的地址信息,所以用一个变量就能够访问整个结点序列。

在上面讲解中出现了两个词:“指向”和“地址”,了解C语言的人可能会知道,这是典型的指针。没错,在C语言中,可以使用指针创建链表。但是在Python中并没有指针的概念,那么应该怎样创建链表呢?我们先来看如何使用Python交换两个值。首先是定义两个变量,代码如下:

x=13
y=14

利用Python交换两个变量代码如下:

x,y =y,x

在Python中交换值可以这样做,但在别的语言中不可以。这是因为在Python中,在定义x=13时,除了开辟一块内存给13这个值,还需要开辟一块内存用于存储13的地址,这块地址称之为x。类似地,在定义y=14时,除了开辟一块内存给14这个值,还需要开辟一块内存用于存储14的地址,这块称之为y。所以说,在Python中交换两个数的值,其实是地址的指向发生转换,类似于C语言中的指针。

在“x,y = y,x”中,我们先看右边,“y,x”的值分别为14,13。即得到“x,y =14,13”。然后x再存储14的地址,y再存储13的地址,这样就达到交换的效果。

在这里插入图片描述

因此,Python中的变量名保存的不是值,而是地址。同时,由于在Python中变量是隐式说明,所以Python中x可以指向任何东西。

了解地址在Python代码中的保存形式之后,就用Python代码实现利用结点创建一个链表的功能。代码如下:

"""
功能:定义类,作用是指向下一个结点。
"""

class Node():
    def __init__(self,elem):        	# 链表元素
        self.elem =elem
        self.next = None       			# 初始设置下一结点为空

创建学生链表,具体代码如下:

"""
功能:创建学生结点类
"""

class student:
    def __init__(self):
        self.name = ''
        self.sex = ''
        self.next = None

head=student()                                          	# 建立链表头部
head.next=None                                        		# 下一个元素为空
ptr=head                                            		# 储存指针的位置
select=0                                             		# 用来选择

while select!=2:                                         	# 不为2就循环
    print("(1)添加 (2)退出程序")                           	# 提示
    select = int(input('请输入一个选项:'))
    if select==1:                                       	# 选择1时,添加信息
        NewData=student()                             		# 添加下一个元素
        NewData.no = input("学号:")                     	# 添加学号
        NewData.name=input("姓名:")                 		# 添加姓名
        NewData.sex=input("性别:")                   		# 添加性别
        ptr.next=NewData                            		# 存储指针设置为新元素所在的位置
        NewData.next=None                        			# 下一个元素的next先设置为空
        ptr=ptr.next                                 		# 指向下一个结点
    elif select == 2:                                    	# 选择2时退出程序
       break
    else:                                          			# 选择其他时提示有误
        print("输入有误")

接下来创建一个链表类并初始化类,代码如下:

"""
功能:定义链表
"""

class LinkList():
    # 使用一个默认参数,传入头结点时则接收,没有传入时,则默认头结点为空
    def __init__(self, node=None ):
        self.__head = node       							# 表示私有属性,不对外开放

然后对这个链表进行基本的操作:

(1)在链表类中,定义一个方法is_empty(),它的功能是判断这个链表是否为空,代码如下:

"""
功能:判断链表是否为空
"""

# def is_empty(self):
    return self.__head == None

(2)在链表类中,定义一个方法LinkList_length(),它的功能是求链表的长度,代码如下:

"""
功能:求链表长度
"""

def LinkList_length(self):
    # cur游标,用来移动遍历结点
    cur = self.__head
    # count记录数量
    count = 0
    while cur != None:
        count += 1
        cur = cur.next
    return count

(3)在链表类中,定义一个方法LinkList_travel(),它的功能是遍历整个链表,代码如下:

"""
功能:遍历整个链表
"""

def LinkList_travel(self):
    cur = self.__head                  		# 指向头结点
    while cur != None:
        print(cur.elem, end=' ')            # 输出链表元素
        cur = cur.next                 		# 指向下一个结点
    print()

2. 单向链表结点的添加

单向链表结点添加分为头结点添加、尾结点添加以及在指定位置添加结点。

在这里插入图片描述
头结点变成了新添加学生的结点,然后新添加的学生next结点指向“学生一”的地址。用Python实现在头结点添加的功能,具体代码如下:

"""
功能:在头部添加新数据,item是数据
"""

def add(self, item):
    node = Node(item)            		# 添加新数据
    node.next = self.__head          	# 新数据的next指向原来的头结点
    self.__head = node             		# 新添加的数据变成头结点

在这里插入图片描述
当新添加学生的结点添加到“学生四”的结点后面,需要将链表最后的“学生四”的结点指向新添加学生的结点,接着将新添加学生的结点指向None。用Python实现在尾结点添加结点的功能,具体代码如下:

"""
功能:在尾部添加新数据,item是数据
"""

def append(self, item):
    # 这里的item是一个数据,不是结点
    node = Node(item)                  					# 新添加数据的结点
    # 由于特殊情况当链表为空时没有next,所以在前面要先做判断
    if self.is_empty():
        self.__head = node              				# 直接向把新添加信息给头结点
    else:                            					# 链表不为空
        cur = self.__head                				# 初始化cur游标
        while cur.next != None:            				# 判断游标指向空,就跳出循环
            cur = cur.next
        cur.next = node                					# 指向新添加数据的结点

在这里插入图片描述

可以看出,在“学生二”的结点和“学生三”的结点之间添加新学生的结点,需要将“学生二”的结点指向“新学生”的结点,然后将“新学生”的结点指向“学生三”的结点,这样就完成了在链表的中间位置添加结点的功能。

"""
功能:在中间位置添加新数据,item是数据
"""

def insert(self, pos, item):

    if pos <= 0:                               		# 如果pos位置在0或者以前,那么都当作头插法来做
        self.add(item)
    elif pos > self.LinkList_length()-1:            # 如果pos位置比原链表长,那么都当作尾插法来做
        self.append(item)
    else:                              				# 否则,采用中间位置添加
        node = Node(item)               			# 新数据的结点
        count = 0
        pre = self.__head
        while count<(pos-1):
            count += 1
            pre = pre.next
        # 当循环退出后,pre指向pos-1位置
        node.next = pre.next
        pre.next = node

3. 链表添加数据,具体代码如下:

"""
功能:定义结点类,作用是指向下一个结点
"""
class Node():
    def __init__(self, elem):
        self.elem = elem
        self.next = None

"""
功能:定义链表
"""
class LinkList(object):
    # 使用一个默认参数,传入头结点时则接收,没有传入时则默认头结点为空
    def __init__(self,node=None):
        self.__head = node   		# __表示私有属性,不对外开放

    """
    功能:判断链表是否为空
    """
    def is_empty(self):
      return self.__head == None


    """
    功能:求链表长度
    """
    def LinkList_length(self):
        # cur游标,用来移动遍历节点
        cur = self.__head
        # count记录数量
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count

    """
    功能:遍历整个链表
    """
    def LinkList_travel(self):
        cur = self.__head            		# 指向头结点
        while cur != None:
             print(cur.elem, end=' ') 		# 输出链表元素
             cur = cur.next          		# 指向下一个结点
        print()

    """
    功能:在头部添加新数据,item是数据
    """
    def add(self, item):
        node = Node(item)          			# 添加新数据
        node.next = self.__head      		# 新数据的next指向原来的头结点
        self.__head = node         			# 新添加的数据变成头结点

    """
    功能:在尾部添加新数据,item是数据
    """
    def append(self, item):
        # 这里的item是一个数据,不是节点
        node = Node(item)        			# 新添加数据的结点
        # 由于特殊情况当链表为空时没有next,所以在前面要先做判断
        if self.is_empty():
            self.__head = node    			# 直接把新添加信息给头结点
        else:                               # 链表不为空
            cur = self.__head       		# 初始化cur游标
            while cur.next != None: 		# 判断游标指向空,就跳出循环
                cur = cur.next
            cur.next = node        			# 指向新添加数据的结点

    """
    功能:在中间位置添加新数据,item是数据
    """
    def insert(self, pos, item):
        if pos <= 0:                		# 如果pos≤0,就调用“头部添加数据”函数
            self.add(item)
        # 如果pos位置比原链表长,就调用“尾部添加数据”函数
        elif pos > self.LinkList_length() - 1: 
            self.append(item)
        else:                   			# 否则,采用中间位置添加
            node = Node(item)    			# 新数据的结点
            count = 0
            pre = self.__head
            while count < (pos - 1):
                count += 1
                pre = pre.next
            # 当循环退出后,pre指向pos-1位置
            node.next = pre.next
            pre.next = node

 

LinkList_demo = LinkList()            		# 创建链表
LinkList_demo.add(25)              			# 调用add()函数在头结点添加数据
LinkList_demo.add(10)              			# 调用add()函数在头结点添加数据
LinkList_demo.append(39)            		# 调用append()函数在尾结点添加数据
LinkList_demo.insert(2, 49)             	# 调用insert()函数在第3个结点(结点下标从0开始)添加数据
LinkList_demo.insert(4, 54)            		# 调用insert()函数在第5个结点(结点下标从0开始)添加数据
LinkList_demo.insert(0, 60)             	# 调用insert()函数在第1个结点(结点下标从0开始)添加数据

# 调用LinkList_length()函数输出链表长度
print ("链表的长度是:",LinkList_demo.LinkList_length())
print("链表的各个数据分别是:")
LinkList_demo.LinkList_travel()        		# 调用LinkList_travel()函数输出链表各个数据

4. 单向链表结点的删除

在这里插入图片描述
可以看出,想删除“学生一”的结点,只要把链表中“学生一”这个头结点(head)指向“学生二”的结点,把“学生二”变成头结点(head)。

例如,“学生一”的结点是node,用Python算法实现,代码如下:

node=head         		# 要删除的结点是头结点
head = head.next      	# 现在是第二个结点变成头结点

在这里插入图片描述

可以看出,删除最后一个结点很简单,就是将链表的倒数第二个结点(即“学生三”的结点)指向none即可。例如倒数第二个结点为p,用Python算法实现,代码如下:

p.next=none               	# 原来p结点指向删除的none结点
p.next=None                	# 现在的p结点指向None

在这里插入图片描述
可以看出,如果要删除链表内的结点,只要将待删除结点的前一个结点p指向要删除结点的下一个结点即可。

例如,删除的结点为y,用Python算法实现代码如下:

y=p.next                      	# 删除结点
p.next=y.next                   # 上一个结点等于删除结点的下一个结点

链表删除数据,具体代码如下:

import sys

"""
功能:创建链表结点
"""
class student:
    def __init__(self):
        self.number=0                          	# 学生学号
        self.name=''                           	# 学生姓名
        self.sex = ''                         	# 学生性别
        self.next=None                          # 指向下一个结点

"""
功能:删除链表中的结点
"""
def del_ptr(head,ptr):
    top=head                                 	# 指向链表头结点
    if ptr.number==head.number:               	# 删除链表头结点
        head=head.next
        print('已删除学号 %d 同学 姓名:%s 性别:%s' %(ptr.number,ptr.name,ptr.sex))
    else:
        while top.next!=ptr:                 	# 找到删除结点的前一个位置
            top=top.next
        if ptr.next==None:                    	# 删除链表末尾的结点
            top.next=None
            print('已删除学号 %d 同学 姓名:%s 性别:%s' %(ptr.number,ptr.name,ptr.sex))
        else:
            top.next=ptr.next                   # 删除链表中的任意一个结点
            print('已删除学号 %d 同学 姓名:%s 性别:%s' %(ptr.number,ptr.name,ptr.sex))
    return head                             	# 返回链表

findword=0
name_data=['Luck','Talon','Mark','Bill']      		# 学生姓名
data=[[1,"Woman"],[2,"Man"],[3,"Man"],[4,"Man"]]  	# 学生学号、性别
print('学号 性别 ')
print('-----------')

for i in range(4):                            		# 遍历输出链表数据
    for j in range(1):
        print('%2d   %3s  ' %(data[j+i][0],data[j*2+i][1]),end='')
    print()
head=student()                              		# 建立链表头部

if not head:
    print('Error!! 内存分配失败!!')
    sys.exit(0)

head.number=data[0][0]                         		# 初始化头结点学号
head.name=name_data[0]                       		# 初始化头结点姓名
head.sex=data[0][1]                           		# 初始化头结点性别
head.next=None
ptr=head

for i in range(1,4):                            	# 建立链表
    new_node=student()
    new_node.number=data[i][0]
    new_node.name=name_data[i]
    new_node.sex=data[i][1]
    new_node.number=data[i][0]
    new_node.next=None
    ptr.next=new_node
    ptr=ptr.next

        

while(True):
    findword=int(input('请输入要删除的学号,输入0表示结束删除过程,请输入:'))
    if(findword==0):                              	# 循环中断条件,输入0程序结束
        break	
    else:                                       	# 否则,根据学号删除学生
        ptr=head
        find=0
        while ptr!=None:
            if ptr.number==findword:                # 判断学号是否在链表中,是则删除
                ptr=del_ptr(head,ptr)               # 调用删除函数
                find=find+1
                head=ptr
            ptr=ptr.next
        if find==0:
            print('没有找到')
      
ptr=head
print('\t学号    姓名\t性别')                      	# 打印剩余链表中的数据
print('\t----------------------------')

while(ptr!=None):
    print('\t%2d\t    %-5s\t%3s' %(ptr.number,ptr.name,ptr.sex))
    ptr=ptr.next
print('\t----------------------------')

5. 单向链表的连接

在这里插入图片描述

可以看出,链表的连接是将head1链表的最后一个结点连接到head2指向的链表的头结点,这样就可以完成链表的连接。

例如,p是连接两个链表之后的大链表指针,用Python代码实现连接的算法如下:

p=head1                          		# 指向头结点为head1的链表
while p.next!=None:                  	# p.next直到为None时,表示head1到尾结点,跳出循环
    p=p.next                    		# 循环指向head1链表的结点
    p.next=head2                		# 将head1的尾结点链接到head2的头结点上

连接两个职员链表,具体代码如下:

import sys
import random

"""
功能:将两个职员链表连接
参数:head1:职员1链表头结点
     head2:职员1链表头结点
"""
def connect_list(head1, head2):
    p = head1                                		# 指向头结点为head1的链表
    while p.next != None:                         	# p.next直到为None时,表示head1到了尾结点,跳出循环
        p = p.next                             		# 循环指向head1链表的结点
    p.next = head2                             		# 将head1的尾结点链接到head2的头结点上
    return head1

class employee:                                		# 创建职员结点
    def __init__(self):
        self.num = 0                           		# 职员工位号
        self.salary = 0                         	# 职员薪资
        self.name = ''                          	# 职员姓名
        self.next = None                        	# 指向下一个结点

findword = 0
data = [[None] * 2 for row in range(4)]            	# 列表推导式
employee_data1 = ['张三', '李四', '王五', '刘六'] 		# 链表1职员姓名
employee_data2 = ['狗剩', '二狗', '铁蛋', '钢镚'] 		# 链表2职员姓名

for i in range(4):                          		# 遍历职员
    data[i][0] = i + 1
    data[i][1] = random.randint(5000, 10000)    	# 随机在(5000, 10000)之间生成薪资

head1 = employee()                            		# 建立第一组链表的头部
if not head1:
    print('Error!! 内存分配失败!!')
    sys.exit(0)

head1.num = data[0][0]                         		# 职员1链表头部工位号
head1.name = employee_data1[0]                  	# 职员1链表头部姓名
head1.salary = data[0][1]                        	# 职员1链表头部薪资
head1.next = None                           		# 指向尾结点
p = head1
for i in range(1, 4):                             	# 建立第一组链表
    new_node = employee()
    new_node.num = data[i][0]                  		# 职员1链表工位号
    new_node.name = employee_data1[i]        		# 职员1链表姓名
    new_node.salary = data[i][1]                  	# 职员1链表薪资
    new_node.next = None
    p.next = new_node
    p = p.next
for i in range(4):
    data[i][0] = i + 5
    data[i][1] = random.randint(5100, 10000)

head2 = employee()                                 	# 建立第二组链表的头部(和第一组链表一样)
if not head2:
    print('Error!! 内存分配失败!!')
    sys.exit(0)

head2.num = data[0][0]
head2.name = employee_data2[0]
head2.salary = data[0][1]
head2.next = None
p = head2
for i in range(1, 4):                           	# 建立第二组链表
    new_node = employee()
    new_node.num = data[i][0]
    new_node.name = employee_data2[i]
    new_node.salary = data[i][1]
    new_node.next = None
    p.next = new_node
    p = p.next

i = 0
p = connect_list(head1, head2)                		# 调用connect_list()函数将链表相连
print('两个链表相连的结果为:')
while p != None:                                  	# 打印链表的数据
    print("◆",p.num," " *3,p.name," "*3,p.salary,"◇" )
    print()
    p = p.next

6. 单向链表的反转

了解单向链表的添加和删除操作之后,发现在链表结构中添加结点和删除结点都比较容易,从头到尾输出链表也不是什么难事。这是因为我们知道单向链表中的每个结点都会指向下一个结点,知道了一个结点的位置,整个链表的每个结点就都知道了。但是如果想反转过来输出链表,知道一个链表的位置,却不能知道此结点的上一个结点位置,该如何入手呢?

在这里插入图片描述
在Python算法中,实现单向链表反转的具体代码如下:

"""
功能:链表反转
参数:head是链表的头结点
"""
def reverse(head):
    p= head               	# 定义变量p指向head
    q=None              	# q是p的前一个结点

    while p!=None:
        a=q             	# 将a接到q之后
        q=p              	# 将q接到p之后
        p=p.next          	# p移到下一个结点
        q.next=a           	# q连接到之前的结点
    return q

从代码中可以看到,实现单向链表反转需要用到三个变量:p、q、a,接下来我们来看这一段程序的反转过程。

步骤1:执行while语句前,变量p指向了头结点,变量q为空,此时链表的情况如图所示。

图21  各变量初始状态

步骤2:执行第一次while循环,借助变量a,将变量a接到变量q之后,将变量q接到变量p之后,变量p结点向下一个结点移动,再将变量q连接到之前的结点,此时链表的情况如图所示。

图22  执行第一次循环

步骤3:执行第二次while循环,这次将变量q的位置交接给变量a,变量p的位置交接给变量q,变量p再向下一个节点移动,最后将变量q的结点连接到之前的结点变量a上,此时链表的情况如图所示。

图23  执行第二次循环

步骤4:执行第三次循环,再次将变量q交接给变量a,变量p交接给变量q,变量p再向下一个结点移动,然后变量q连接到之前的结点变量a上,此时链表的情况如图所示。

图24  执行第三次循环

直到p=None时,整个单向链表就反转过来了,最终链表反转如图25所示。

图25  链表反转

反转学生链表,具体代码如下:

import sys

"""
功能:创建链表结点
"""
class student:
    def __init__(self):
        self.number=0                                			# 学生的学号
        self.name=''                                  			# 学生的姓名
        self.sex = ''                                   		# 学生的性别
        self.next=''

findword=0
name_data=['Luck','Talon','Mark','Bill']                        # 链表学生名字
data=[[1,"Woman"],[2,"Man"],[3,"Man"],[4,"Man"]]              	# 链表学生学号和性别
head=student()                                              	# 建立链表头部
if not head:
    print('Error!! 内存分配失败!!')
    sys.exit(0)

head.number=data[0][0]                                       	# 链表头部学生学号
head.name=name_data[0]                                      	# 链表头部学生姓名
head.sex=data[0][1]                                          	# 链表头部学生性别
head.next=None
ptr=head
for i in range(1,4):                                         	# 建立链表
    new_node=student()
    new_node.number=data[i][0]                             		# 初始化链表学生学号
    new_node.name=name_data[i]                              	# 初始化链表学生姓名
    new_node.sex=data[i][1]                               		# 初始化链表学生性别
    new_node.next=None
    ptr.next=new_node                                   		# 指向学生链表下一个结点
    ptr=ptr.next

ptr=head
i=0
print('反转前的学生链表结点数据:')
while ptr !=None:                                       		# 打印链表数据
    print('☆ %2d\t  %-1s\t%-3s  ☆' %(ptr.number,ptr.name,ptr.sex), end='')
    i=i+1
    if i>=1:                                           			# 一个数据为一行
        print()
        i=0
    ptr=ptr.next                                        		# 指向下一个结点

ptr=head
before=None  
print('\n反转后的学生链表结点数据:')
while ptr!=None:                                        		# 链表反转,利用三个指针,反转指针核心
    last=before
    before=ptr
    ptr=ptr.next
    before.next=last

ptr=before
while ptr!=None:                                        		# 打印链表数据
    print('★ %2d\t  %-1s\t%-3s   ★' %(ptr.number,ptr.name,ptr.sex), end='')
    i=i+1
    if i>=1:                                         			# 一个数据为一行
        print()
        i=0
    ptr=ptr.next

7. 堆栈、队列与链表

堆栈与队列都是比较抽象的数据结构,它们在计算机领域的应用都很广。堆栈多用于递归调用。堆栈简单来说就是将数据一层一层堆积起来,要想获取数据,需要先将后堆的数据取出,堆栈的数据结构是典型的“后进先出”结构。生活中也有很多类似堆栈的例子,例如装卸货车,把商品一层一层堆在货车上,卸货车时,需要从最后堆的上面一层开始卸。

在这里插入图片描述
而队列不同,队列就像排队一样,刚来的人入队时要排在队尾,每次出队的都是队首的人,它的数据结构是典型的“先进先出”。

在这里插入图片描述

7.1 用链表实现堆栈

使用链表实现堆栈的优点是可以随时动态改变链表的长度,能有效地利用内存空间,保证不浪费内存,实现用多大就申请多大的内存空间的功能。但这种功能有利也有弊,它的缺点就是设计的算法有点复杂。但是理解了堆栈的本质,该算法也不难理解,接下来我们来看用Python链表算法如何实现堆栈。

(1)声明堆栈的链表结点

"""
功能:定义堆栈链表结点类
"""
class Node:
    def __init__(self):
        self.data=0            	# 声明堆栈数据
        self.next=None         	# 堆栈用来指向下一个结点

top=None                      	# 声明顶端并初始化

(2)判断堆栈链表是否为空

"""
功能:判断堆栈链表是否为空
"""
def is_empty():
    global top               	# 将top声明为全局变量
    if(top==None):           	# 顶端为None
        return 1            	# 返回1
    else:                  		# 否则
        return 0            	# 返回0

(3)将数据压入堆栈

"""

功能:将数据压入堆栈中

"""

def push(data):
    global top
    new_node=Node()           		# 新结点
    new_node.data=data           	# 将数据指定为结点的内容
    new_node.next=top           	# 将新结点指向堆栈的顶端
    top=new_node              		# 新结点成为堆栈的顶端

(4)将数据弹出堆栈(从堆栈中取数据)

"""
功能:将数据弹出
"""
def pop():
    global top
    if is_empty():                      	# 判断堆栈链表是否为空
        print("当前堆栈链表为空")
        return -1                      		# 退出程序
    else:
        p=top                       		# 指向堆栈的顶端
        top=top.next                   		# 将堆栈顶端指向下一个结点
        temp=p.data                   		# 弹出数据
        return temp                     	# 将从堆栈中弹出的数据返回给主程序

使用链表实现堆栈

"""

功能:定义堆栈链表结点类

"""

class Node:

	def __init__(self):
        self.data=0                  	# 声明堆栈数据
        self.next=None              	# 堆栈来指向下一个结点
	top=None                         	# 声明顶端并初始化

"""
功能:判断堆栈链表是否为空
"""
def is_empty():
    global top                       	# 将top声明为全局变量
    if(top==None):                   	# 顶端为None
        return 1                     	# 返回1
    else:                          		# 否则
        return 0                     	# 返回0

"""
功能:将数据压入堆栈中
"""
def push(data):
    global top
    new_node=Node()                 	# 新结点
    new_node.data=data                	# 将数据指定为结点的内容
    new_node.next=top                 	# 将新结点指向堆栈的顶端
    top=new_node                    	# 新结点成为堆栈的顶端

"""
功能:将数据弹出
"""
def pop():
    global top
    if is_empty():                 		# 判断堆栈链表为空
        print("当前堆栈链表为空")
        return -1                 		# 退出程序
    else:
        p=top                   		# 指向堆栈的顶端
        top=top.next               		# 将堆栈顶端指向下一个结点
        temp=p.data              		# 弹出数据
        return temp               		# 将从堆栈中弹出的数据返回给主程序

while True:
    i=int(input("1:向堆栈中压入数据,2;堆栈中弹出,3:退出堆栈操作:请输入您的选择: "))
    if i==1:
        data = int(input("请输入要压入的数据:"))
        push(data)                 		# 调用堆栈压入数据函数
    elif i==2:
        print("弹出的数据为", pop()) 		# 调用堆栈弹出数据函数
    elif i==3:
        break                   		# 退出堆栈操作,即退出循环

print("---------------------------------------")
while(not is_empty()):              	# 将数据陆续从顶端弹出
    print('堆栈弹出的顺序为:%d' %pop())

print("---------------------------------------")
print("可以看出:先压入的数据后弹出,后压入的数据先弹出")

可以看出压入数据和弹出数据的情况。
在这里插入图片描述

7.2 用链表实现队列

队列也可以用链表实现,在定义队列方法时,要包含指向队列前端和队列末端的指针。接下来我们来看用Python链表算法如何实现队列。

我们用职员的姓名和工号来建立队列。

(1)建立职员队列链表结点

"""
功能:定义职员队列链表
"""
class worker:
    def __init__(self):
        self.name=''*20 	# 职员名字
        self.number=0  		# 职员工位号
        self.next=None 		# 队列中指向下一个结点

fore=worker()
end=worker()
fore=None            		# 队列前端指针
end=None                   	# 队列末尾指针

(2)将数据加入队列中

"""
功能:将数据加入到队列中
参数:name:表示职员名字
      number:表示职员工位号
"""
def add_queue(name,number):
    global fore
    global end
    new_data=worker()               	# 分配内存给新数据
    new_data.name=name              	# 为新数据赋值
    new_data.number=number          	# 为新数据赋值
    if end==None:                    	# 如果end为None,表示这是第一个元素
        fore=new_data
    else:
        end.next=new_data             	# 将新数据连接到队列末尾
    end=new_data                   		# 将end指向新数据,这是新数据的末尾
    new_data.next=None                	# 新数据之后再无其他数据

(3)取出队列中的数据

"""
功能:取出队列中的数据
"""
def out_queue():
    global fore
    global end
    if fore==None:                     						# 如果队列前端为None,表示这个队列为空
        print("队列已经没有数据了")
    else:#否则
        print("姓名:",fore.name," 工号:",fore.number)  		# 输出信息
        fore=fore.next             							# 将队列前端移到下一个元素

使用链表实现职员队列

"""
功能:定义职员队列链表
"""
class worker:
    def __init__(self):
        self.name=''*20                             	# 职员名字
        self.number=0                              		# 职员工位号
        self.next=None                             		# 队列中指向下一个结点
fore=worker()
end=worker()
fore=None                                       		# 队列前端指针
end=None                                       			# 队列末尾指针

"""
功能:将数据加入到队列中
参数:name:表示职员名字
      number:表示职员工位号
"""
def add_queue(name,number):
    global fore
    global end
    new_data=worker()                                 	# 分配内存给新数据
    new_data.name=name                                 	# 为新数据赋值
    new_data.number=number                          	# 为新数据赋值
    if end==None:                                       # 如果end为None,表示这是第一个元素
        fore=new_data
    else:
        end.next=new_data                         		# 将新数据连接到队列末尾
    end=new_data                                        # 将end指向新数据,这是新数据的末尾
    new_data.next=None                           		# 新数据之后再无其他数据

"""
功能:取出队列中的数据
"""
def out_queue():
    global fore
    global end
    if fore==None:                               		# 如果队列前端为None,表示这个队列为空
        print("队列已经没有数据了")
    else:  	# 否则
        print("姓名:",fore.name," 工号:",fore.number)  	# 输出信息
         	# 将队列前端移到下一个元素
        fore=fore.next                           

"""
功能:显示队列中的数据
"""
def show():
    global fore
    global end
    p = fore                                    		# 从队列前端开始
    if p== None:                                		# 判断p为空,则队列为空
        print('队列已空!')                        		# 提示
    else:
        while p != None:                         		# 从队列前端(fore)到队列末尾(end)遍历队列
            print("姓名:",p.name,"\t工号:", p.number)  	# 输出队列信息
            p = p.next                          		# 指向下一个结点

i = 0                                          			# 用于选择变量
while True:
    i = int(input("1:向队列加入数据 2:从队列中取出数据 3:显示队列中数据 4:退出程序,请选择:"))
    if i == 1:                                    		# 选择1
        name = input("姓名: ")                      		# 输出职员姓名
        score = int(input("工位号: "))                   # 输入职员工位号
        add_queue(name, score)                    		# 向队列中加入数据
    elif i == 2:                                   		# 选择2
        out_queue()                             		# 在队列中取出数据
    elif i==3:                                   		# 选择3
        show()                               			# 显示在队列中未取出的数据
    elif i == 4:                                   		# 选择4
            break                            			# 退出程序
    else:                                     			# 否则
        print("输入有误")                         		# 提示输入有误

可以看出在队列中加入数据和取出数据的情况。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_42226855/article/details/131259260
024