1.什么是数据结构
-
官方定于:无
-
民间定义:
-
“数据结构是数据对象 ,以及存在于该对象的实例和 组成实例的数据元素之间的各种联系。这些联系可以通过定义相关的函数来给出。” — 《数据结构、算法与应用》
-
“数据结构(data structure)是计算机中存储、组织数据的方式。通常情况下,精心选择的数据结构可以 带来最优效率的算法。” —中文维基百科
-
“数据结构是ADT(抽象数据类型 Abstract Data Type)的物理实现。” — 《数据结构与算法分析》
什么是抽象数据ADT?
实际上 python 内置的 list 就可以看成一种抽象数据类型。
ADT: Abstract Data Type,抽象数据类型,我们在组合已有的数据结构来实现一种新的数据类型, ADT 定义了类型的数据和操作。
-
2.常见的数据结构
栈、队列、链表、集合、字典、树等
不同的数据结构的不同操作性能是不同的:
- 有的查询性能很快,有的插入速度很快,有的是插入头和尾速度很快
- 有的做范围查找很快,有的允许元素重复,有的不允许重复等等
- 在开发中如何选择,要根据具体的需求来选择
注:数据结构与语言无关
3.什么是算法
算法的定义:
- 一个有限指令集, 每条指令的描述不依赖于语言
- 接受一些输入(有些情况下不需要输入)
- 产生输出
- 一定在有限步骤之后终止
列表
序号 | 方法 |
---|---|
1 | list.append(obj)在列表末尾添加新的对象 |
2 | list.count(obj)统计某个元素在列表中出现的次数 |
3 | list.extend(seq)在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表) |
4 | list.index(obj)从列表中找出某个值第一个匹配项的索引位置 |
5 | list.insert(index, obj)将对象插入列表 |
6 | list.pop(index=-1)移除列表中的一个元素(默认最后一个元素),并且返回该元素的值 |
7 | list.remove(obj)移除列表中某个值的第一个匹配项 |
8 | list.reverse()反向列表中元素 |
9 | list.sort( key=None, reverse=False)对原列表进行排序 |
10 | list.clear()清空列表 |
11 | list.copy()复制列表 |
字典
序号 | 函数及描述 |
---|---|
1 | dict.clear()删除字典内所有元素 |
2 | dict.copy()返回一个字典的浅复制 |
3 | dict.fromkeys()创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值 |
4 | dict.get(key, default=None)返回指定键的值,如果键不在字典中返回 default 设置的默认值 |
5 | key in dict如果键在字典dict里返回true,否则返回false |
6 | dict.items()以列表返回一个视图对象 |
7 | dict.keys()返回一个视图对象 |
8 | dict.setdefault(key, default=None)和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default |
9 | dict.update(dict2)把字典dict2的键/值对更新到dict里 |
10 | dict.values()返回一个视图对象 |
11 | pop(key,default)删除字典 key(键)所对应的值,返回被删除的值。 |
12 | popitem()返回并删除字典中的最后一对键和值。 |
集合
方法 | 描述 |
---|---|
add() | 为集合添加元素 |
clear() | 移除集合中的所有元素 |
copy() | 拷贝一个集合 |
difference() | 返回多个集合的差集 |
difference_update() | 移除集合中的元素,该元素在指定的集合也存在。 |
discard() | 删除集合中指定的元素 |
intersection() | 返回集合的交集 |
intersection_update() | 返回集合的交集。 |
isdisjoint() | 判断两个集合是否包含相同的元素,如果没有返回 True,否则返回 False。 |
issubset() | 判断指定集合是否为该方法参数集合的子集。 |
issuperset() | 判断该方法的参数集合是否为指定集合的子集 |
pop() | 随机移除元素 |
remove() | 移除指定元素 |
symmetric_difference() | 返回两个集合中不重复的元素集合。 |
symmetric_difference_update() | 移除当前集合中在另外一个指定集合相同的元素,并将另外一个指定集合中不同的元素插入到当前集合中。 |
union() | 返回两个集合的并集 |
update() | 给集合添加元素 |
len() | 计算集合元素个数 |
数组
数组是最常用到的一种线性结构,python 内置了一个 array 模块,但是不常使用。
Python 的 array 是内存连续、存储的都是同一数据类型的结构,而且只能存数值和字符。
数组提供了高效的、固定类型的一维数组。相比于列表,array
对象节省了空间且在处理大量同类型数据时速度更快。
栈
栈(stack),它是一种运算受限的线性表,后进先出(LIFO)
- LIFO(last in first out)表示就是后进入的元素, 第一个弹出栈空间. 类似于自动餐托盘, 最后放上的托盘, 往往先把拿出去使用.
- 其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。
- 向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;
- 从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
栈常见的操作
push(element)
: 添加一个新元素到栈顶位置.pop()
:移除栈顶的元素,同时返回被移除的元素。peek()
:返回栈顶的元素,不对栈做任何修改(这个方法不会移除栈顶的元素,仅仅返回它)。isEmpty()
:如果栈里没有任何元素就返回true
,否则返回false
。clear()
:移除栈里的所有元素。size()
:返回栈里的元素个数。这个方法和数组的length
属性很类似。
class Stack:
def __init__(self):
self.item = []
def push(self, element):
self.item.append(element)
def pop(self):
return self.item.pop()
def peek(self):
return self.item[-1]
def is_empty(self):
return len(self.item) == 0
def clear(self):
self.item.clear()
def size(self):
return len(self.item)
s1 = Stack()
s1.push(1)
s1.push(123)
s1.push("abcd")
print(s1.size())
print(s1.peek())
print(s1.pop())
s1.clear()
队列
队列(Queue),它是一种运算受限的线性表,先进先出(FIFO First In First Out)
- 队列是一种受限的线性结构
- 受限之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作
队列常见的操作
enqueue(element)
:向队列尾部添加一个(或多个)新的项。dequeue()
:移除队列的第一(即排在队列最前面的)项,并返回被移除的元素。front()
:返回当前队列中第一个元素,也将是最先被移除的元素。队列不做任何变动(不移除元素,只返回元素信息——与Stack
类的peek
方法非常类似)。isEmpty()
:如果队列中不包含任何元素,返回true
,否则返回false
。size()
:返回队列包含的元素个数,与数组的length
属性类似.
1.普通队列
class Queue:
def __init__(self):
self.item = []
def is_empty(self):
return len(self.item) == 0
def enqueue(self, element):
self.item.append(element)
def dequeue(self):
if self.is_empty():
return None
return self.item.pop(0)
def front(self):
if self.is_empty():
return None
return self.item[0]
def size(self):
return len(self.item)
q1 = Queue()
q1.enqueue(123)
q1.enqueue("abc")
q1.enqueue(666)
print(q1.size())
print(q1.front())
print(q1.dequeue())
print(q1.size())
2.优先级队列
优先级队列的特点:
- 我们知道, 普通的队列插入一个元素, 数据会被放在后端. 并且需要前面所有的元素都处理完成后才会处理前面的数据.
- 但是优先级队列, 在插入一个元素的时候会考虑该数据的优先级.(和其他数据优先级进行比较)
- 比较完成后, 可以得出这个元素正确的队列中的位置. 其他处理方式, 和队列的处理方式一样.
- 也就是说, 如果我们要实现优先级队列, 最主要是要修改添加方法. (当然, 还需要以某种方式来保存元素的优先级)
实现优先级队列相对队列主要有两方面需要考虑:
-
- 封装元素和优先级放在一起(可以封装一个新的类)
-
- 添加元素时, 将当前的优先级和队列中已经存在的元素优先级进行比较, 以获得自己正确的位置.
class Pqueue:
class Element:
def __init__(self, el, rank):
self.el = el
self.rank = rank
def __init__(self):
self.item = []
def is_empty(self):
return len(self.item) == 0
def enqueue(self, el, rank):
en_element = self.Element(el, rank)
if self.is_empty():
self.item.append(en_element)
else:
flag = True
for i in range(len(self.item)):
if en_element.rank < self.item[i].rank:
self.item.insert(i, en_element)
flag = False
break
if flag:
self.item.append(en_element)
def dequeue(self):
if self.is_empty():
return None
return self.item.pop(0)
def front(self):
if self.is_empty():
return None
return self.item[0]
def size(self):
return len(self.item)
q1 = Pqueue()
q1.enqueue(123, 2)
q1.enqueue("abc", 1)
q1.enqueue(666, 3)
q1.enqueue(987, 4)
print(q1.size())
print(q1.front().el)
print(q1.dequeue().el)
链表
链表是链式的存储多个元素.
- 但不同于列表, 链表中的元素在内存中不必是连续的空间
- 链表的每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(有些语言称为指针或者链接)组成
- 链表访问任何一个位置的元素时, 都需要从头开始访问.(无法跳过第一个元素访问任何一个元素)
链表常见的操作
-
append(element)
:向列表尾部添加一个新的项 -
insert(position, element)
:向列表的特定位置插入一个新的项。 -
remove(element)
:从列表中移除一项。 -
indexOf(element)
:返回元素在链表中的索引。如果列表中没有该元素则返回-1
。 -
removeAt(position)
:从列表的特定位置移除一项。 -
isEmpty()
:如果链表中不包含任何元素,返回true
,如果链表长度大于0则返回false
。 -
size()
:返回链表包含的元素个数。与数组的length
属性类似。
1.单链表
class Node:
def __init__(self, el):
self.el = el
self.next = None
class Linklist:
def __init__(self):
self.head = None
self.length = 0
def is_empty(self):
return self.length == 0
def append(self, element):
node = Node(element)
if self.is_empty():
self.head = node
else:
node_next = self.head
while node_next.next is not None:
node_next = node_next.next
node_next.next = node
self.length += 1
def index_of(self, element):
node_next = self.head
for i in range(self.length):
if node_next.el == element:
return i
node_next = node_next.next
print("未找到该元素!")
def insert(self, position, element):
if position < 0 or position > self.length:
return False
node = Node(element)
node_next = self.head
previous = None
if position == 0:
node.next = node_next
self.head = node
else:
for i in range(position + 1):
previous = node_next
node_next = node_next.next
previous.next = node
node.next = node_next
self.length += 1
return True
def remove_at(self, position):
if position < 0 or position > self.length:
return False
node_next = self.head
previous = None
if position == 0:
self.head = node_next.next
else:
for i in range(position):
previous = node_next
node_next = node_next.next
previous.next = node_next.next
self.length -= 1
return node_next.el
def remove(self, el):
index = self.index_of(el)
return self.remove_at(index)
def size(self):
return self.length
list1 = Linklist()
for i in range(6):
list1.append(i)
print(list1.index_of("hello"))
print(list1.index_of(4))
print(list1.remove(4))
print(list1.size())