1-21天学习挑战赛之经典算法

算法

算法是将输入转为输出的一系列计算步骤,在计算机中执行时通常先用伪代码进行表示

伪代码

伪代码(Pseudocode)是一种非正式的,类似于英语结构的,用于描述模块结构图的语言。
人们在用不同的编程语言实现同一个算法时意识到,他们的实现(注意:这里是实现,不是功能)很不同。使用伪代码的目的是使被描述的算法可以容易地以任何一种编程语言(Pascal,C,Java等)实现。因此,**伪代码必须结构清晰、代码简单、可读性好,并且类似自然语言。**介于自然语言与编程语言之间。

数据结构

使用不同的数据结构存储数据,对应的算法可能千差万别

  1. 数据结构研究的是如何按一定的逻辑结构,把数据组织起来,并选择适当的存储表示方法把逻辑结构组织好的数据存储到计算机的存储器里。
  2. 算法研究的目的是为了更有效的处理数据,提高数据运算效率。
  3. 数据的运算是定义在数据的逻辑结构上,但运算的具体实现要在存储结构上进行。一般有以下几种常用运算:
    (1)检索。检索就是在数据结构里查找满足一定条件的节点。一般是给定一个某字段的值,找具有该字段值的节点。
    (2)插入。往数据结构中增加新的节点。
    (3)删除。把指定的结点从数据结构中去掉。
    (4)更新。改变指定节点的一个或多个字段的值。
    (5)排序。把节点按某种指定的顺序重新排列。例如递增或递减。
  4. 常见的数据结构包括数组、堆、栈、队列、链表、树、图等。

算法效率

算法的复杂性体运行该算法时的计算机所需资源的多少上,计算机资源最重要的是时间和空间(即寄存器)资源,因此复杂度分为时间和空间复杂度
时间复杂度是指执行算法所需要的计算工作量
空间复杂度是指执行这个算法所需要的内存空间

时间复杂度

一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度,记为T(n),也就是算法的时间复杂度,也是使用算法的最坏情况复杂度,大多数情况为输入的数据量
一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f (n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度,O代表数量级。
在各种不同算法中,若算法中语句执行次数为一个常数,则时间复杂度为O(1)。
另外,时间频度不相同时,时间复杂度有可能相同,如T(n)=n2+3n+4与T(n)=4n2+2n+1它们的频度不同,但时间复杂度相同,都为O(n2)。

空间复杂度

程序从开始执行到结束所需的最大内存容量,不考虑输入数据空间

查找

在某种数据结构中找出满足给定条件(关键字key)的元素,分为顺序查找、折半查找、索引查找

顺序查找

输入

序列和关键词key

算法说明

从序列一端,挨个元素进行比较

伪代码

i = 1
while i <= A.length
    if A[i] == key
        return i
    i++
return -1

算法实现

python内置函数顺序查找
mylist = [1,2,3,4,5,6]
print(5 in mylist)		# 查找5是否在列表中
print(mylist.index(5))	# 返回第一个数据5的下标
print(mylist.index(5,2,5))  # 返回从下标2到5(不含)查找数据5
print(mylist.count(5))	# 返回数据5的个数
#输出
1
2
3
4
5
遍历有序列表
def sequential_search(list, key):
    for i in range(len(list)):
        if list[i] == key:
            return i
    else:
        return False
if __name__ == '__main__':
    list_0 = [1,2,3,4,5,6,7,8,9,10]
    result0 = sequential_search(list_0, 10)
    result1 = sequential_search(list_0, 11)
    print(result0, result1)
#输出
9 False
遍历无序列表

在无序列表中查找一个值时需要使用遍历技术。在访问每个节点时,需要比较它的数据是否与要查找的数据相符。这样,可能不用遍历全部的节点就能找到,如果找到了就不必继续找下去。如果我们真到了列表的尾部,就说明没找到。

节点

第一步是构建节点,这是遍历有序列表和无序列表操作中最重要的步骤
节点(Node)是链表实现的基本构造,由列表项(item,数据字段)(节点自身的数据,称为“数据域”)和对下一个节点的引用组成。
Node类包含包括访问、修改数据以及访问下一个引用等常用方法。
另外还需要注意节点类和链表中的一个特殊节点:None,对None的引用代表没有下一个节点。例如在构造函数中,就是创建一个节点,把并它的“引用”赋值为None。在初始化一个“引用”时,可以先将其赋值为None,这样省时省力,具体代码如下:

# 创建节点类Node,节点(Node)是实现链表的基本模块
class Node:
	def __init__(self, initdata):
		self.data = initdata
		self.next = None
	def getData(self):
		return self.data
	def getNext(self):
		return self.next
	def setData(self, newdata):
		self.data - newdata
	def setNext(self, newnext):
		self.next = newnext
无序列表类UnorderedList

创建无序列表类UnorderedList,无序列表通过一个节点的集合来实现,每个节点包括对下一个节点的引用。
设计原理是:只要找到第一个节点,跟着引用就能走遍每一个数据项。按照这个设计原理,必须在无序列表类中保存对第一个节点的引用。
在下面类UnorderedList的实现代码中,需要注意每个列表对象包含了对“列表头”(head)的引用。代码如下:

#创建无序列表类UnorderedList
class UnorderdList:
	def __init__(self):
		self.head = None
#在上述代码中编写了方法isEmpty(),其功能是检查head引用是否是None。方法isEmpty()中的返回值是表达式self.head==None,只有当链表中没有节点时为真。既然一个新建链表是空,则构造函数和方法isEmpty()必须保持一致,这也显示了用None来代表“结束”的优势。在Python语言中,None能够和任意的引用作比较,如果两个变量引用了同一对象,那么它们就是相等的。
	def isEmpty(self):
		return self.head == None
#编写方法add()把新的数据项加入列表,在添加之前需要处理一个重要问题:链表把新数据项放在什么位置?既然列表是无序的,那么新数据项的位置与原有元素关系不大,新数据项可放在任意位置。这样,可以把新数据项放在最容易处理的位置。
	def add(self, item):
		temp = Node(item)
		temp.setNext(self.head)
		self.head = temp
#方法size()、search()和remove()都是基于链表的遍历技术实现的,遍历是指系统地访问每个节点的过程。从第一个节点的外部引用开始,每访问过一个节点,通过引用移动到下一个节点实现遍历。
#为了实现方法size(),也需要遍历链表,在这个过程中用一个变量记录经过的节点。通过代码count=count+1实行了计数器功能,最后通过current进行外部引用。
	def size(self):
		current = self.head
		count = 0
		while current != None:
			#在开始时因为没有经历过任何节点,所以计数器变量为0,然后实现了遍历
			count = count + 1
			#只要current引用没有看到None,就把current指向下一个节点,
			current = current.getNext()
		return count
	def search(self, item):
		current = self.head
		found = False
		while current != None and not found:
			if current.getData() == item:
				found = True
			else:
				current = current.getNext()
		return found
#在上述代码中,方法remove()需要两个步骤。
#首先需要遍历列表找到要删除的数据,找到后再进行删除操作。这一步功能和查找相似,都是实现遍历列表并找到这个数据功能。因为假定数据是存在的,所以一定在到达None之前找到,我们使用found的布尔值来标志是否找到。找到后,found变成True,current就是对包含要删除的数据的节点的引用。
#另外还有一种可能的方式是用一种标志代替原来的数值,表明这个数值不存在。但这样一来,链表的节点数量和实际的数量对不上,所以不如直接删除这个节点。为了删除一个节点,需要把待删除节点前面那个节点的next指向待删除节点后面那个节点即可。但是,在找到current以后,我们没有办法再回到它前面,因为这已经来不及修改。
#解决办法是在遍历时使用两个外部引用,current表示当前正在遍历的。然后将新的引用称为previous,将其跟在current后面进行遍历,这样当current找到要删除节点时,previous正好停在current前面节点上。
	def remove(self, item):
		current = self.head
		previous = None
		found = False
		while not found:
			if current.getData() == item:
				found = True
			else:
				previous = current
				current = current.getNext()
		if previous == None:
			self.head = current.getNext()
		else:
			previous.seteNext(current.getNext())
验证

为了验证我们上面编写的节点类和无序列表处理类,通过以下代码进行测试。

mylist = UnorderdList()
mylist.add(1)
mylist.add(2)
mylist.add(3)
mylist.add(4)
mylist.add(5)
mylist.add(6)
print(mylist.size())
print('查找key=6的索引:', mylist.search(6))
print('--------------')
mylist.remove(6)
print(mylist.size())
print('移除6,查找key=6的索引:', mylist.search(6))
#输出
6
查找key=6的索引: True
--------------
5
移除6,查找key=6的索引: False
应用:求最大、最小值
def Max(alist):
	pos = 0	   # 初始位置
	imax = alist[0]
	while pos < len(alist):
		if alist[pos] > imax:
			imax = alist[pos]
		pos = pos + 1
	return imax
def Min(alist):
	pos = 0
	imin = alist[0]
	for item in alist:
		if item < imin:
			imin = item
	return imin

活动地址:CSDN21天学习挑战赛

学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您:
想系统/深入学习某技术知识点…
一个人摸索学习很难坚持,想组团高效学习…
想写博客但无从下手,急需写作干货注入能量…
热爱写作,愿意让自己成为更好的人…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值