数据结构
顺序存储结构 和 链接存储结构 适用在内存结构中、
索引存储结构 和 散列存储结构 适用在外存与内存交互结构
索引存储:除建立存储结点信息外,还建立附加的索引表来标识结点的地址。索引表由若干索引项组成。
索引存储结构是用结点的索引号来确定结点存储地址,其优点是检索速度快,缺点是增加了附加的索引表,会占用较多的存储空间。
散列存储:又称hash存储,是一种力图将数据元素的存储位置与关键码之间建立确定对应关系的查找技术。
散列法存储的基本思想是:由节点的关键码值决定节点的存储地址。散列技术除了可以用于查找外,还可以用于存储。
特点:
散列是数组存储方式的一种发展,相比数组,散列的数据访问速度要高于数组,因为可以依据存储数据的部分内容找到数据在数组中的存储位置,进而能够快速实现数据的访问,理想的散列访问速度是非常迅速的,而不像在数组中的遍历过程,采用存储数组中内容的部分元素作为映射函数的输入,映射函数的输出就是存储数据的位置,这样的访问速度就省去了遍历数组的实现,因此时间复杂度可以认为为O(1),而数组遍历的时间复杂度为O(n)。
递归是算法中一个比较核心的概念,有三个特点,1 调用自身 2 具有结束条件 3 代码规模逐渐减少
# 递归函数
def fun(x): if x>0: print (x) fun(x-1) fun(9) # 调用函数
两个概念:时间复杂度和空间复杂度
时间复杂度:用于体现算法执行时间的快慢,用O表示。一般常用的有:几次循环就为O(n几次方) 循环减半的O(logn)
空间复杂度:用来评估算法内存占用大小的一个式子,通常情况下会选择使用空间换时间
列表查找:从列表中查找指定元素
输入:列表、待查找元素
输出:元素下标或未查找到元素
version 1 顺序查找:从列表中的第一个元素开始,顺序进行搜索,直到找到为止,复杂度为O(n)
version 2 二分查找:从有序列表中,通过待查值与中间值比较,以减半的方式进行查找,复杂度为O(logn)
快排的时间复杂度最佳情况是O(nlogn),最差情况是O(n^2)
冒泡排序:列表中每相邻两个如果顺序不是我们预期的大小排列,则交换。时间复杂度O(n^2)
选择排序:一趟遍历选择最小的数放在第一位,再进行下一次遍历直到最后一个元素。复杂度依然为O(n^2)
插入排序:将列表分为有序区和无序区,最开始的有序区只有一个元素,每次从无序区选择一个元素按大小插到有序区中. 复杂度依然为O(n^2)
二叉树的储存方式有:1 链式储存 2 顺序储存(列表)
```
数据结构用于解决数据的逻辑关系和存储问题,而算法用于处理和分析数据
```
```
稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;
内排序:所有排序操作都在内存中完成;
外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行;
```
```
"时间复杂度"
时间复杂度是指执行算法所需要的计算次数、是一个函数、描述算法的运行时间、
时间复杂度常用[大O符号]表述,不包括这个函数的低阶项和首项系数、称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度
"空间复杂度"
空间复杂度是指执行算法所需要的内存空间、临时占用存储空间大小的量度、它也是问题规模n的函数,记做S(n)=O(f(n))
```
```
常用的时间复杂度的排序
O(1)常数阶 < O(logn)对数阶 < O(n)线性阶 < O(n2)平方阶 < O(n3)(立方阶) < O(2n) (指数阶)
拿时间换空间,用空间换时间
算法的时间复杂度和空间复杂度是可以相互转化的
```
```
数据、数据类型、数据结构、数据元素、数据项、逻辑结构、存储结构、
线性结构、树性结构、图性结构、非线性结构、
顺序存储结构、链式存储结构、索引存储结构、散列存储结构、
线性表、顺序表、链表、栈、队列、
链表结构、数据部分、地址部分(引用部分)
```
```
"程序": 数据结构+算法=程序
"数据": 数据是信息的载体、Data、
"数据类型": 分类数据、确定数据元素存储空间、定义相关操作。
```
```
"数据结构":
数据结构是定义数据的存储方式和逻辑关系的一种数学模型、Data Structure
数据结构包含: 数据的逻辑结构、数据的存储结构、数据的相关运算、
"数据元素":
数据元素是数据的基本单元、也称 结点、记录、顶点. 一个数据元素可以由若干个数据项组成、
数据项是具有独立含义的最小标识单位、数据项也可称之为 字段、域、属性等.
"数据结构"、Array数组、Stack栈、Queue队列、Linked List链表、Tree树、Graph图、Heap堆、Hash散列表
```
```
"逻辑结构"
数据的逻辑结构,就是指的数据之间的逻辑关系,
线性结构用于存储具有一对一逻辑关系、一个结点元素最多有一个直接前驱和一个直接后继
非线性结构其逻辑特征是一个结点元素可能有多个直接前驱和多个直接后继
树形结构用于存储具有一对多关系的数据
图形结构用于存储具有多对多关系的数据
"存储结构"
数据的存储结构也就是物理结构指的是数据在物理存储空间上选择集中存放还是分散存放
数据存储结构的选择取决于两方面即数据的逻辑结构和存储结构(物理结构)
集中存储(底层实现使用的是数组)需要使用一大块连续的物理空间、集中存储就是使用顺序存储结构
链式存储是随机存储数据,随机在物理内存空间分配较小的空间进行数据存储、无需连续物理空间、成功的概率高
数据集中存储有利于后期对数据进行遍历操作
数据分散存储有利于后期增加或删除指定数据
```
```
"数据的逻辑结构":
数据的逻辑结构是数据元素之间的逻辑关系、相互关系、Logical Structure
"数据的存储结构":
数据的存储结构是数据元素及其逻辑关系在计算机存储器中的组织形式、Storage Structure
"数据的相关运算":
数据的运算是能够对数据施加的操作、数据运算包括、检索、插入、删除、更新、排序等
```
```
"线性结构":
线性结构就是数据元素之间具有线性关系、存在一对一的相互关系、数据元素呈线性分布、
线性结构有且仅有一个开始结点和一个结束结点、线性结构所有结点最多只有一个前驱结点和一个后继结点。
"非线性结构":
非线性结构就是数据各个结点之间具有多个对应关系、非线性结构的一个结点有可能有多个前驱结点和多个后继结点、
如: 数组、广义表、树结构、图结构都是非线性结构
"集合" 数据结构中的元素之间除了“同属一个集合” 的相互关系外,别无其他关系;
"线性结构" 数据结构中的元素存在一对一的相互关系;
"树性结构" 数据结构中的元素存在一对多的相互关系;
"图形结构" 数据结构中的元素存在多对多的相互关系。
```
```
数据结构的存储方式
"顺序存储"、Sequential
顺序存储是在一块连续的存储空间依次存放数据、把逻辑上相邻的结点存储在物理位置上相邻的存储单元里、
结点之间的逻辑关系由存储单元的邻接关系体现、顺序存储方式也称顺序存储结构、一般采用数组、结构数组来描述
"链式存储"、Linked
链式存储不要求逻辑上相邻的结点物理位置上相邻、结点间的逻辑关系由附加的引用字段表示、一个结点的引用字段通常指向下一个结点的存储位置、
链式存储方式也称链式存储结构、一般在原数据元素的数据项中增加引用项来表示结点之间的关系
"索引存储"、Index
索引存储方式是采用附加索引表的方式来存储结点信息的一种存储方式、索引表由若干索引项组成、
索引存储方式中索引项的一般形式为:关键字、地址、关键字能够为一标识一个结点的数据项
索引存储:除建立存储结点信息外,还建立附加的索引表来标识结点的地址。索引表由若干索引项组成。
索引存储结构是用结点的索引号来确定结点存储地址,其优点是检索速度快,缺点是增加了附加的索引表,会占用较多的存储空间。
稠密索引:每个结点在索引表中都有一个索引项、索引项的地址指示结点所在的存储位置
稀疏索引:一组结点在索引表中只对应一个索引项、索引项的地址只是一组结点的起始存储位置
"散列存储"、Hash
散列存储是根据结点的关键字直接计算出该结点的存储地址的一种存储方式
散列存储:又称hash存储,是一种力图将数据元素的存储位置与关键码之间建立确定对应关系的查找技术。
散列法存储的基本思想是:由节点的关键码值决定节点的存储地址。散列技术除了可以用于查找外,还可以用于存储。
顺序存储结构 和 链接存储结构 适用在内存结构中、
索引存储结构 和 散列存储结构 适用在外存与内存交互结构
```
```
"线性表"
线性表逻辑结构为线性结构、存储结构可以是顺序存储结构、链式存储结构、线性表中的数据元素具有相同的数据类型和长度、
线性表的元素具有线性关系、连续内存空间依次存储数据、存储相同类型的元素、线性表包含顺序表和链表、
"顺序表"
顺序表的逻辑结构为线性结构、存储结构为顺序存储结构、顺序表中的数据元素具有相同的数据类型和长度、
顺序表会提前申请一整块足够大小的连续的物理内存空间,然后将数据依次紧密存储起来,顺序表存储数据使用的就是数组
顺序表是连续内存空间存放数据、只要知道顺序表的首地址及每个元素所占的存储长度、就可以知道每个元素(结点)的位置。
顺序存储结构、要求内存空间连续、在插入或者删除结点时、往往需要移动大量的数据、
如果数据表比较大、有时比较难分配足够的连续存储空间、导致内存分配失败而无法存储。
"链表"
链表的逻辑结构为线性结构、存储结构为链式存储结构、链表中的数据元素具有相同的数据类型和长度、
数据依次存储在分散的物理空间中,通过引用保存着它们之间的逻辑关系,链式存储结构(简称链表);
链表存储的数据元素,其物理存储位置是随机的,并通过指针/引用表示数据之间的逻辑关系
链表结构动态分配存储空间、可以根据需要动态申请所需的内存单元、不要求内存空间连续。
链表结构由于采用了引用来指示下一个数据的地址、因此链表结构在逻辑上相邻的结点在内存中并不一定相邻、逻辑相邻关系通过地址部分的引用变量来实现。
链表结构带来的最大好处便是结点之间不要求连续存放、因此保存大量数据时、不需要分配一个连续的内存存储空间、用户可以动态分配结点的存储空间、当删除结点时、给结点赋值null、释放其占用的内存空间。
链表结点都包含两部分内容:数据部分、地址部分(引用部分)
"数据部分"、保存的是该结点的实际数据信息
"地址部分"、保存的是下一个结点的地址信息
```
```
数据结构大致包含以下几种存储结构:
线性表,还可细分为顺序表、链表、栈和队列;
树结构,包括普通树,二叉树,线索二叉树等;
图存储结构;
```
```
"基本数据类型"、其值不能分解、整数、浮点
"聚合数据类型"、其值可以分解为若干分量、用户自定义类型、数组、结构体、
```
```
"数组":
聚合数据类型、线性逻辑结构、顺序存储结构、相同类型数据元素的集合、是一个典型的线性表、Array
数据是线性结构的线性表,数组元素类型和长度相同
计算机为数组分配一段连续的内存,从而支持对数组随机访问;
由于数据元素的地址在编号上是连续的,数组某一项的地址可以通过将两个值相加得出,即将数组的基本地址和项的偏移地址相加。
数组地址就是数组的第一项的机器地址。
一个数据元素的偏移地址就等于它的索引乘以数组的一个数据元素所需要的内存单元数目的一个常量表示(在python中,这个值总是1)
```
```
"栈"
栈是一种特殊的线性表、遵循后进先出原则(LIFO)、仅允许在表的一端进行插入和删除运算。
只有栈顶元素可以访问、两个基本操作 入栈Push、出栈Pop、
"入栈"将数据保存到栈顶的操作、"出栈"将栈顶的数据弹出的操作
栈可以分为 顺序结构栈、链式结构栈
顺序栈与链栈 两种实现方式的区别,仅限于数据元素在实际物理空间上存放的相对位置,顺序栈底层采用的是[数组],链栈底层采用的是[链表]
```
```
"队列"
队列是一种特殊线性结构、遵循先进先出原则(FIFO)、仅允许在一端进行插入 在另一端进行删除运算。
队列可以分为 顺序结构队列、链式结构队列、
```
```
栈:是一种容器、可以保存、访问、删除元素.
栈只允许在容器的一端进行操作、没有位置的概念、
任何时候可以访问、删除的元素都是之前最后存入的那个元素、
栈是按照后进先出的原理运作
```
class Stack(object): # 创建一个新的空栈 def __init__(self): self.__list = [] def push(self, item): # 添加一个新的元素item到栈顶 self.__list.append(item) def pop(self): # 弹出栈顶元素 return self __list.pop() def peek(self): # 返回栈顶元素 if self.__list: return self.__list[-1] else: return None def is_empty(self): # 判断栈是否为空 return not self__list def size(self): # 返回栈的元素个数 return len(self.__list)
```
队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表
队列是一种先进先出的线性表、简称FIFO.
允许插入的一端为队尾、允许删除的一端为队头.
队列不允许在中间部位进行操作.
```
class Queue(object): def __init__(self): self.__list = [] def enqueue(self,item): self.__list.append(item) def dequeue(self): return slef.pop(0) def is_empty(self): return self.__list == [] def size(self): return len(self.__list)
```
双端队列、是一种具有队列和栈的性质的数据结构
双端队列中的元素可以从两端弹出、其限定插入和删除操作在表的两端进行、
双端队列可以在队列任意一端入队和出队
```
class Deque(object): def __init__(self): self.__list = [] def add_front(self, item): self.__list.insert(0, item) def add_rear(self, item): self.__list.append(item) def pop_front(self): return self.__list.pop(0) def pop_rear(self): return self.__list.pop() def is_empty(self): return self.__list == [] def size(self): return len(self.__list)