数据结构和算法(python语言描述):(时间复杂度,顺序表,链表,栈队列)(排序,二分查找,树的遍历,对文件操作)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_43435675/article/details/88572439

0.时间复杂度

# 如果a+b+c=1000,且a^2+b^2=c^2(a,b,c为自然数),如何求出所有a,b,c可能的组合?
import time
start_time = time.time()
for a in range(0,1001):
    for b in range(0,1001):
        for c in range(0,1001):
            if a+b+c==1000 and a**2+b**2==c**2:
                print('a,b,c:%d,%d,%d'%(a,b,c))
end_time = time.time()
print('time:%d'%(end_time-start_time))
print('finished')

输出

a,b,c:0,500,500
a,b,c:200,375,425
a,b,c:375,200,425
a,b,c:500,0,500
time:203
finished

在这里插入图片描述
在这里插入图片描述
下图练习第一个O(1),第二个O(n),第三个O(n^2),第四个O(n ^3)
在这里插入图片描述
下图为用函数为列表添加元素,因为函数是基本步骤的封装,所以不能算作1步:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

def test1():
   li = []
   for i in range(10000):
      li.append(i)

def test2():
   li = []
   for i in range(10000):
     li = li + [i]
    
def test3():
   li = [i for i in range(10000)]

def test4():
   li = list(range(10000))

def test5():
    li = []
    for i in range(10000):
        li.extend([i])

def test6():
   li = []
   for i in range(10000):
      li.insert(0,i)     
    
    
from timeit import Timer

t1 = Timer("test1()", "from __main__ import test1")
print("append:",t1.timeit(1000))

t2 = Timer("test2()", "from __main__ import test2")
print("+: ",t2.timeit(1000))

t3 = Timer("test3()", "from __main__ import test3")
print("[i for i in range]:",t3.timeit(1000))

t4 = Timer("test4()", "from __main__ import test4")
print("list(range()): ",t4.timeit(1000))

t5 = Timer("test5()", "from __main__ import test5")
print("extend: ",t5.timeit(1000))

t6 = Timer("test6()", "from __main__ import test6")
print("insert(0): ",t6.timeit(1000)) # append从队尾加,insert从对头加,时间差大

append: 0.9385726000000432
+: 203.88772059999974
[i for i in range]: 0.43753339999966556
list(range()): 0.2188015000001542
extend: 1.3811896000006527
insert(0): 46.54819399999997

1.顺序表

程序=数据结构+算法。下图为数据的存储:1个int数占4个字节(B)(1B=8bit),都是int型按顺序存放即顺序表方便查找
在这里插入图片描述
在这里插入图片描述
下图左边为顺序表基本形式,右边为元素外置形式(存地址)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一体式如果存储空间不够,连表头信息都要换。
在这里插入图片描述
在这里插入图片描述

2.链表

顺序表要求存储空间必须连续,一旦不够就要动态改变数据区。
线性表分为顺序表和链表,下图为链表,不用改变原数据结构,多一个加一个。
在这里插入图片描述
如下图实现两数交换:第三行到第四行:先=号右边,再=号左边
在这里插入图片描述
如下图若int a=10,a是别名,不代表另一块存储空间
在这里插入图片描述
下面为代码实现自己封装的链表:类,对象,属性,方法
在这里插入图片描述
在这里插入图片描述
下图为add头部插元素方法:
在这里插入图片描述
下面为指定位置插,下图理解python中=号,间接:
在这里插入图片描述
在这里插入图片描述
下图为删除节点:
在这里插入图片描述
在这里插入图片描述

class Node(object):# node=Node(100),这个节点保存100这个数
    """节点"""
    def __init__(self,elem): # self在__init__自动跳出,接收elem
        self.elem = elem # 节点有elem和next属性,将elem保存到节点对象中
        self.next = None

        
class SingleLinkList(object):
    """单链表"""
    
    def __init__(self,node=None): #注意中间,号 #init方法
        self._head = node  #_为私有属性,保存头节点信息
        
        
    def is_empty(self):
        """链表是否为空"""
        return self._head == None
    
    
    def length(self):
        """链表长度"""
        cur = self._head  # cur游标,用来移动遍历节点
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count

    
    def travel(self):
        """遍历链表"""    
        cur = self._head
        while cur != None:
            print(cur.elem,end=" ")
            cur = cur.next
        
        
    def add(self, item):
        """头部添加节点"""
        node = Node(item)#构造新节点node
        node.next = self._head#先 
        self._head = node#后

        
    def append(self, item):
        """尾部添加节点"""
        node = Node(item)#构造新节点node
        if self.is_empty():
            self._head = node#直接加新节点
        else:
            cur = self._head #指向头节点
            while cur.next != None:
                cur = cur.next
            cur.next = node # 尾部添加新的node      

            
    def insert(self, pos, item):
        """在指定位置添加节点"""
        #:param pos从0开始
        if pos <= 0:                 
            self.add(item) #头插法
        elif pos > (self.length()-1):
            self.append(item) #pos(0,1,2...)>长度,进行尾插法
        else:
            pre = self._head
            count = 0
            # 移动到了指定位置的前一个位置
            while count < (pos-1):
                count += 1
                pre = pre.next
            # 当循环退出后,pre指向pos-1位置
            node = Node(item)
            node.next = pre.next
            pre.next = node

            
    def remove(self, item):
        """删除一个节点"""
        cur = self._head
        pre = None
        while cur != None:
            if cur.elem == item: #用户想删的item
                if cur == self._head: #要删除的刚好是头节点
                    self._head = cur.next #直接指向下一个
                else:
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next

                
    def search(self, item):#item为用户传进
        """查找节点是否存在"""
        cur = self._head
        while cur != None:
            if cur.elem == item:
                return True
            else: 
                 cur = cur.next
        return False


if __name__ == "__main__":
    ll = SingleLinkList()
    print(ll.is_empty())
    print(ll.length())
    
    ll.append(1)
    print(ll.is_empty())
    print(ll.length())
    
    ll.append(2)
    ll.add(8)
    ll.append(3)
    ll.append(4)
    ll.append(5)
    ll.append(6)
    ll.insert(3,9)
    ll.travel()
    
    print()#换下一行
    ll.remove(9)
    ll.travel()

输出

True
0
False
1
8 1 2 9 3 4 5 6
8 1 2 3 4 5 6

下面为单向循环链表遍历,求长度,添加,删除元素。指定位置插入和单链表一样不用变
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下面为双向链表:下图用了面向对象的继承
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.栈队列

栈:后进先出(和线性表一样都是存储数据,但没有线性表中间尾部取数据等操作)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.六种排序(冒泡选择,插入希尔,快速归并)

排序算法稳定性:如下图按元组中第一个元素大小排序,(维持之前次序)这组稳定。
在这里插入图片描述
在这里插入图片描述
如果一个函数在内部调用它自己,那么这函数就叫递归函数
选择排序从后面无序序列中选一个,放前面最后一位置
插入排序是从后面无序序列中选一个,插入前面有序序列位置中哪一个(从右往左比对)
希尔排序思想是插入排序的改进:对54,77,20按插入排序排,然后26,31排序,,,
在这里插入图片描述
下图第二行是第一行按gap=4排的
在这里插入图片描述

from time import time # 计时装饰器 
def timer(func):     
    def inner(*args,**kwargs):
        start = time()
        result = func(*args,**kwargs)
        end = time()
        usedTime = 1000 * (end - start)
        
        print("%s function used %.2f ms" %(func.__name__,usedTime))
        return result
    return inner
@timer
def bubble_sort(alist): #冒泡排序
    n = len(alist)
    for j in range(n-1):
        for i in range(n-1-j):
            if alist[i]>alist[i+1]:
                alist[i],alist[i+1]=alist[i+1],alist[i]
if __name__ == "__main__":
    blist = list(range(1,3000 + 1))
    import random
    blist = random.sample(blist, k=len(blist))#从blist中随机获取k个元素
    alist = blist[:1000]
    #print(alist)
    bubble_sort(alist)
    print(alist)

输出
在这里插入图片描述

@timer
def select_sort(alist):#选择(遍历)排序,从右边选择最小放左边
    n = len(alist)
    for j in range(n-1):#j:0到n-2
        min_index=j #假的最小值下标动,从第一个开始遍历
        for i in range(j+1,n):
            if alist[min_index]>alist[i]:
                min_index=i
            alist[j],alist[min_index]=alist[min_index],alist[j] 
        #这里min_index为真的最小值下标
if __name__ == "__main__":
    blist = list(range(1,3000 + 1))
    import random
    blist = random.sample(blist, k=len(blist))
    alist = blist[:1000]
    select_sort(alist)
    print(alist)

输出
在这里插入图片描述

@timer
def insert_sort(alist):#插入排序
    n=len(alist)
    for j in range(1,n):#从右边的无序序列中取出多少个元素执行这样的过程
        #j=[1,2,3,n-1]
        #i代表内层循环起始值
        i=j
        #执行从右边的无序序列中取出第一个元素,即i位置的元素
        #然后将其插入到前面的正确位置中
        while i>0:
            if alist[i]<alist[i-1]:
                alist[i],alist[i-1]=alist[i-1],alist[i]
                i-=1
            else:
                break

if __name__ == "__main__":
    blist = list(range(1,3000 + 1))
    import random
    blist = random.sample(blist, k=len(blist))
    alist = blist[:1000]
    insert_sort(alist)
    print(alist)

输出
在这里插入图片描述

@timer
def shell_sort(alist):#希尔排序
    n=len(alist) #n=9
    gap=n//2 #gap=4
    while gap>0:#gap变化到0之前,插入算法执行的次数
        #与普通的插入算法的区别就是gap步长
        for j in range(gap,n):
            i=j #j=[gap,gap+1,gap+2,gap+3,..,n-1]
            while i>0:
                if alist[i]<alist[i-gap]:
                    alist[i],alist[i-gap]=alist[i-gap],alist[i]
                    i-=gap
                else:
                    break
        gap//=2
if __name__ == "__main__":
    blist = list(range(1,3000 + 1))
    import random
    blist = random.sample(blist, k=len(blist))
    alist = blist[:1000]
    shell_sort(alist)
    print(alist)

输出
在这里插入图片描述
前面的排序方法都分为左右两部分。快排中若low指的元素比54大停走,high指的元素比54小停走,则low和high指的元素互相交换,继续往中间走。重合时low指的前一个元素就是54位置固定了,54的左右边分别继续low和high操作。
在这里插入图片描述

def quick_sort(alist,first,last):#快速排序
    if first>=last:
        return
    mid_value=alist[first]
    low=first  #low和high为游标,first为第一个元素,last为最后一元素
    high=last
    while low<high:#没有相遇
        while low<high and alist[high]>=mid_value:
            high-=1 #high左移
        alist[low]=alist[high]#元素交换,游标不交换
        
        while low<high and alist[low]<mid_value:
            low+=1
        alist[high]=alist[low]
        
    #从循环退出时,low==high
    alist[low]=mid_value
    
    #对low左边的列表执行快速排序
    quick_sort(alist,first,low-1)
     
    #对low右边的列表执行快速排序
    quick_sort(alist,low+1,last)

def main():
    blist = list(range(1,3000 + 1))
    import random
    blist = random.sample(blist, k=len(blist))
    alist = blist[:1000]
    quick_sort(alist,0,len(alist)-1)
    print(alist)
main()

下图拆分两部分,直到只有一个元素
在这里插入图片描述
上图先26和17比,17小拿出来right指针往后移。26再和93比,26小将26拿出来排在17后

在这里插入图片描述
在这里插入图片描述

5.二分查找

下面为搜索:二分查找:对象只能是顺序表:(0+8)/2=4找到下标为4的数字7。(0+3)/2=1(取整)对应的3。(2+3)/2=2(取整)对应的4。
在这里插入图片描述

item为要查找的元素:
在这里插入图片描述
非递归和快排差不多,用first和last指明查找的范围
在这里插入图片描述
下面为二分查找时间复杂度,2的几次方=n(序列长度)。
如果按遍历来查找,时间复杂度为O(n)。
在这里插入图片描述

6.树的遍历

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下面为广度层次横向遍历:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下图先序(先根):根左右
中序:左根右(从左到右即从下到上)
后序:左右根(从左到右即从下到上)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.python对文件操作

1.增:写入文件内容给文本文件

def writeTextFile(filePath, fileContent, encoding='utf8'):
    with open(filePath, 'w', encoding=encoding) as file:
        file.write(fileContent)

2.删

3.改:批量修改图片大小

import os
from PIL import Image

def getFilePathList(dirPath, partOfFileName=''):
    allFileName_list = list(os.walk(dirPath))[0][2]
    fileName_list = [k for k in allFileName_list if partOfFileName in k]
    filePath_list = [os.path.join(dirPath, k) for k in fileName_list]
    return filePath_list

def batchResizeImage(oldDirPath, newDirPath, height, width):
    if not os.path.isdir(newDirPath):
        os.mkdir(newDirPath)
    jpgFilePath_list = getFilePathList(oldDirPath, '.jpg')
    for jpgFilePath in jpgFilePath_list:
        image = Image.open(jpgFilePath)
        resized_image = image.resize((height, weight), Image.ANTIALIAS)
        jpgFileName = os.path.split(jpgFilePath)[1]
        saveFilePath = os.path.join(newDirPath, jpgFileName)
        resized_image.save(saveFilePath)
        
oldDirPath = 'source_images'
newDirPath = 'train_images'
height = 640
width = 640
batchResizeImage(oldDirPath, newDirPath, height, width)

4.查:查询文件夹中的文件

import os

def getFileNameList(dirPath, partOfFileName=''):
    allFileName_list = list(os.walk(dirPath))[0][2]
    fileName_list = [k for k in allFileName_list if partOfFileName in k]
    return fileName_list
    
def getFilePathList(dirPath, partOfFileName=''):
    allFileName_list = list(os.walk(dirPath))[0][2]
    fileName_list = [k for k in allFileName_list if partOfFileName in k]
    filePath_list = [os.path.join(dirPath, k) for k in fileName_list]
    return filePath_list

查:读取文件

def readTextFile(filePath, encoding='utf8'):
    with open(filePath, encoding=encoding) as file:
        return file.read()

查:搜索文件夹路径内含有指定内容的代码文件

import os
# 传入3个参数:文件夹路径dirPath、指定内容partOfFileContent、代码文件后缀名suffixOfFileName
def searchFileContent(dirPath, partOfFileContent, suffixOfFileName=''):
    dirPath = os.path.expanduser(dirPath)
    walk_list = list(os.walk(dirPath))
    result_list = []
    for walk in walk_list:
        filePath_list = [os.path.join(walk[0], k) for k in walk[2] \
            if k.rsplit('.', maxsplit=1)[1]==suffixOfFileName.strip('.')]
        for filePath in filePath_list:
            with open(filePath, encoding='=utf8') as file:
                fileContent = file.read()
            if partOfFileContent in fileContent:W
                print(filePath)
                result_list.append(filePath)
    return result_list

猜你喜欢

转载自blog.csdn.net/weixin_43435675/article/details/88572439