单链表,双向链表,循环链表

数据结构:
    
    定义:
        特定的数据类型(个体)和特定的存储结构(个体的关系)
        数据如何存储在内存中
    分类:
        
        线性结构:
        数据元素之间存在一对一的线性关系。线性结构拥有两种不同的存储结构,即顺序存储结构和链式存储结构。
        
            数组与列表:顺序存储结构
                
                相同点:
                    需要申请一块连续的内存空间

                不同点:
                    列表或者数组中的元素是如何存储的,以及两者的区别?
                        在其他语言中(C/C++)数组申请的内存空间是一定的, 比如申请10M的内存空间,如果数据超过10M会溢出,需要手动申请和释放
                        在python中不会出现溢出报错这种问题,底层做了处理会自动扩展,不需要手动申请和释放
                        
                        python:                            
                            li = [1,2,3,4,54,56,56,67,77]
                        C/C++:
                            malloc()         申请                
                            free()            释放
                        
                    列表提供了哪些最基本的操作?
                        append(), insert(), pop()等
                     
                    这些操作的时间复杂度是多少?
                        插入时间复杂度:O(n)   因为数组是连续存放的,后面的数据会后移
                        查找时间复杂度: O(1)      按照索引运算查找即可
                        
                    为啥数组(列表)的索引或者下标是从0开始?
                        减少运算的压力 查找内存位置的时候直接按照索引算即可,如果从1开始还要减一
                    
                关于数组(列表)的优缺点:
                    优点:
                        查找快
                    
                    缺点:
                        插入慢
                        要求一块 连续 的内存空间 ***
            
                
            链表:链式存储结构
                插入时间复杂度:O(1)        
                查找时间复杂度: O(n)
                
                链表的优点:
                    1、不需要一块连续内存空间
                    2、相对于数组来说,插入较简单
                
                单链表
                双链表
                循环链表 约瑟夫问题
                
                链表算法:增删改查以及总长度
            
            应用:
                栈
                
                队列
            
            
        非线性结构: 
            树作为一种应用广泛的一对多非线性数据结构,不仅有数据间的指向关系,还有层级关系
            如何在内存中表示呢?
            
            树                
            
            图
                图论
介绍
###########################
# 单链表:水浒英雄排序
# 双向链表多一个pre

class Hero:
    def __init__(self,name=None,no=None,nickname=None,pNext=None):
        self.name = name
        self.no = no
        self.nickname = nickname
        self.pNext = pNext

# 直接添加到尾部
def add(head,pnew):
    cur = head
    while cur.pNext != None:
        cur = cur.pNext
    cur.pNext = pnew

# 指定位置进行添加
def insert(head,pnew):
    cur = head
    while cur.pNext != None:
        if cur.pNext.no > pnew.no:
            break
        cur = cur.pNext
    pnew.pNext = cur.pNext
    cur.pNext = pnew

# 根据no删除某个节点(英雄)
def delHero(head,no):
    cur = head
    while cur.pNext != None:
        if cur.pNext.no == no:
            break
        cur = cur.pNext
    else:
        print("没有此元素")
    cur.pNext = cur.pNext.pNext

# 查看单链表是否为空
def is_empty(head):
    if head.pNext == None:
        return True
    else:
        return False

# 计算单链表长度
def length(head):
    cnt = 0
    cur = head
    while cur.pNext != None:
        cur = cur.pNext
        cnt += 1
    return cnt

# 打印所有的单链表数据
def getAll(head):
    cur = head
    while cur.pNext != None:
        cur = cur.pNext
        print('编号是:%s,姓名是:%s,外号:%s' %(cur.no,cur.name,cur.nickname))

head = Hero()

h1 = Hero('宋江',1,'及时雨')
add(head,h1)

h2 = Hero('卢俊义',2,'玉麒麟')
add(head,h2)

h3 = Hero('吴用',3,'智多星')
add(head,h3)

h4 = Hero('马波',5,'波神')
add(head,h4)

h5 = Hero('波老师',4,'波波')
add(head,h5)

print(length(head))
getAll(head)
###########################
单链表
###########################
# 循环链表:解决约瑟夫问题
# 设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,
# 数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列

class Child:
    first = None
    def __init__(self,data = None,pNext = None):
        self.data = data
        self.pNext = pNext
# 生成n个小朋友,构成循环链表
    def add(self,num):
        cur = None
        for i in range(num):
            child = Child(i+1)
            if i == 0: # 当i=0时,构成一个循环链表,指向自己,目的是:后面的好加入
                self.first = child #first指向第一个孩子对象
                self.first.pNext = self.first #第一个孩子的指针指向自己构成循环链表
                cur = self.first
            else:
                cur.pNext = child
                child.pNext = self.first
                cur = cur.pNext
# 展示所有的小孩
    def showAll(self):
        cur = self.first #第一个孩子节点
        while cur.pNext != self.first: #只有末尾的节点指针指向第一个节点
            print('小孩的编号是:%s' %cur.data)
            cur=cur.pNext
        print('小孩的编号是:%s' %cur.data) #打印末尾节点的编号

# 解决约瑟夫问题
    def countChild(self,m,k):
        tail = self.first #第一个孩子节点,

        while tail.pNext != self.first: #除了最后一个节点外,都是True
            tail = tail.pNext
        # 退出循环的话,已经到了最后一个小朋友,就在first后面

        # tail是用来出列之后修复循环链表,永远在first后面,执行完上面的代码就在first后面了

        # 从哪里开始数,first移动到报数位置,tail在first后面
        for i in range(k-1):
            self.first = self.first.pNext
            tail = tail.pNext

        while tail != self.first: # 退出循环的时候,圈子里面只剩一个人
            # 数2下,first、tail前移1下
            # 数3下,first、tail前移2下
            # 数m下,first、tail前移m-1下
            for i in range(m - 1):
                self.first = self.first.pNext
                tail = tail.pNext
            # 修复循环链表
            self.first = self.first.pNext
            tail.pNext = self.first
        print('留在圈子里面的小孩编号:%s' %tail.data)

child = Child() #生成对象
child.add(1000)  #添加100个小孩
# child.showAll() #打印100个小孩的编号
child.countChild(1000,300) #从编号为3的人开始,数到80的人出列
###########################
循环链表

猜你喜欢

转载自www.cnblogs.com/xujinjin18/p/9972746.html