数据结构与算法
1、什么是数据结构
我认为的数据结构就是计算机中存储、组织数据的方式
在《数据结构与算法分析》一书中,把数据结构称为抽象数据类型(ADT)
而什么又是ADT呢?
ADT,抽象数据类型,我们在组合已有的数据结构来实现一种新的数据类型,ADT定义了类型的数据和操作
我们以抽象一个背包(Bag) 数据类型来说明,背包是一种容器类型,我们可以给它添加东西,也可以移除东西,并且我们想知道背包里有多少东西。于是我们可以定义一个新的数据类型叫做 Bag,在类中实现背包的所有功能.
class Bag:
""" 背包类型 """
pass
2、栈
栈(stack)是一种运算受限的线性表,他符合先进后出的一个原则,就是最先进去的数据反而是最后出来的。
类似于平时收作业,先收到的作业放在最下面,后收到的作业放在最上面。发作业的时候后收到的作业先发出去,先收到的作业后发出去。
栈的限制就是只允许在表的一端进行插入和删除,这一端被称为栈顶,而另外一端被称为栈底。
向栈内添加一个元素被称为进栈(入栈、压栈)它是把新的元素放在栈顶元素的上面。让该元素称为新的栈顶元素。
从栈内取出数据又叫出栈或退栈,它是把栈顶元素删除掉,使其下面的元素成为新的栈顶元素。
栈常见的操作
push(element)
: 添加一个新元素到栈顶位置.pop()
:移除栈顶的元素,同时返回被移除的元素。peek()
:返回栈顶的元素,不对栈做任何修改(这个方法不会移除栈顶的元素,仅仅返回它)。isEmpty()
:如果栈里没有任何元素就返回true
,否则返回false
。clear()
:移除栈里的所有元素。size()
:返回栈里的元素个数。这个方法和数组的length
属性很类似。
栈的实现:
class Stack:
def __init__(self):
#初始化一个私有变量用来存储之后的数据对象
self.__items = []
#添加一个新元素到栈顶位置
def push(self,element):
self.__items.append(element)
#移除栈顶的元素,同时返回被移除的元素。
def pop(self):
return self.__items.pop()
#返回栈顶的元素,不对栈做任何修改(这个方法不会移除栈顶的元素,仅仅返回它)
def peek(self):
return self.__items[-1]
#如果栈里没有任何元素就返回`true`,否则返回`false`。
def is_empty(self):
return len(self.__items)==0
#移除栈里的所有元素
def clear(self):
self.__items.clear()
#返回栈里的元素个数。这个方法和数组的`length`属性很类似。
def size(self):
return len(self.__items)
3、队列
队列(queue),它也是一种运算受限的线性表,它遵循一个先进先出原则。
它的受限之处在于它只允许在表的前端进行删除操作,而在表的后端进行添加操作。
就类似于生活中的排队打饭,先排队的先打饭然后离开,后来的人只能排在队伍的末尾,要等前面的人离开后,后面的人才能打饭。
队列常见的操作
enqueue(element)
:向队列尾部添加一个(或多个)新的项。dequeue()
:移除队列的第一(即排在队列最前面的)项,并返回被移除的元素。front()
:返回当前队列中第一个元素,也将是最先被移除的元素。队列不做任何变动(不移除元素,只返回元素信息——与Stack
类的peek
方法非常类似)。isEmpty()
:如果队列中不包含任何元素,返回true
,否则返回false
。size()
:返回队列包含的元素个数,与数组的length
属性类似.
普通队列的实现
class Queue:
def __init__(self):
self.__items = []
def enqueue(self,element):
self.__items.append(element)
def dequeue(self):
if len(self.__items)==0:
return None
self.__items.pop(0)
def front(self):
if len(self.__items)==0:
return None
return self.__items[0]
def is_empty(self):
return len(self.__items)==0
def size(self):
return len(self.__items)
优先级队列
优先级队列的特点:
- 我们知道, 普通的队列插入一个元素, 数据会被放在后端. 并且需要前面所有的元素都处理完成后才会处理前面的数据.
- 但是优先级队列, 在插入一个元素的时候会考虑该数据的优先级.(和其他数据优先级进行比较)
- 比较完成后, 可以得出这个元素正确的队列中的位置. 其他处理方式, 和队列的处理方式一样.
- 也就是说, 如果我们要实现优先级队列, 最主要是要修改添加方法. (当然, 还需要以某种方式来保存元素的优先级)
优先级队列的实现:
实现优先级队列相对队列主要有两方面需要考虑:
1、封装元素和优先级放在一起(可以封装一个新的类)
2、添加元素时, 将当前的优先级和队列中已经存在的元素优先级进行比较, 以获得自己正确的位置.
class Node:
def __init__(self,element,rank):
self.element = element
self.rank = rank
class Queue:
def __init__(self):
self.__items = []
def enqueue(self,element,rank):
node = Node(element,rank)
flag = True
for i in range(len(self.__items)):
if node.rank < self.__items[i].rank:
self.__items.insert(i,node)
flag = False
break
if flag:
self.__items.append(node)
def dequeue(self):
if self.is_empty():
return None
return self.__items.pop(0)
def front(self):
if self.is_empty():
return None
return self.__items[0]
def is_empty(self):
return len(self.__items) == 0
def size(self):
return len(self.__items)
q2=Queue()
q2.enqueue("jack2",1)
q2.enqueue("jack3",1)
q2.enqueue("jack",2)
q2.enqueue("jack4",2)
q2.enqueue("jack3",3)
q2.enqueue("karen",1)
print("取出优先队列中的第一个元素:",q2.dequeue().element)
print("取出优先队列中的第一个元素:",q2.dequeue().element)
print("取出优先队列中的第一个元素:",q2.dequeue().element)
4、链表
链表是链式的存储多个元素
但不同于列表,链表中的元素在内存中不必是连续的空间
链表的每一个元素由一个存储元素本身的节点和一个指向下一个元素的引用(有些语言也称指针或者链接)组成。
链表访问任何一个位置的元素时,都需要从头开始访问(无法跳过第一个元素访问任何一个元素)
链表常见的操作
-
append(element)
:向列表尾部添加一个新的项 -
insert(position, element)
:向列表的特定位置插入一个新的项。 -
remove(element)
:从列表中移除一项。 -
indexOf(element)
:返回元素在链表中的索引。如果列表中没有该元素则返回-1
。 -
removeAt(position)
:从列表的特定位置移除一项。 -
isEmpty()
:如果链表中不包含任何元素,返回true
,如果链表长度大于0则返回false
。 -
size()
:返回链表包含的元素个数。与数组的length
属性类似。
1、单向链表的实现
class Node:
def __init__(self,element):
self.element = element
self.next = None
class Linklist:
def __init__(self):
self.length = 0
self.head = None
def append(self,element):
node = Node(element)
if self.head == None:
self.head = node
else:
temp = self.head
while temp.next != None:
temp = temp.next
temp.next = node
self.length += 1
def insert(self, position, element):
# 检测越界问题: 越界插入失败
if (position < 0 or position > self.length):
return False
# 定义变量, 保存信息
newNode = Node(element)
current = self.head
previous = None
index = 0
if (position == 0):
newNode.next = current
self.head = newNode
else:
while (index < position):
previous = current
current = current.next
index += 1
newNode.next = current
previous.next = newNode
self.length += 1
return True
def index_of(self,element):
if self.head == None:
return None
else:
temp = self.head
for i in range(self.length):
if temp.element == element:
return i
temp = temp.next
return -1
def removeAt(self,position):
# 检测越界问题: 越界移除失败, 返回None
if (position < 0 or position >= self.length):
return None
current = self.head
previous = None
index = 0
if position == 0:
self.head = current.next
else:
while index < position:
previous = current
current = current.next
index += 1
previous.next = current.next
self.length -= 1
return current.element
def remove(self,elemnet):
index = self.index_of(elemnet)
return self.removeAt(index)
def isEmpty(self):
return self.length == 0
# 获取链表的长度
def size(self):
return self.length
list1 = Linklist()
for i in range(6):
list1.append(i)
print(list1.index_of("hello")) # -1
print(list1.index_of(4)) # 4
print(list1.remove(4)) # 4
print(list1.size())