目录

      

      队列

      链表双向链表

      哈希表

       二叉搜索树


what's the 数据结构

  数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。 简单来说,数据结构就是设计数据以何种方式组织并存储在计算机中。 比如:列表、集合与字典等都是一种数据结构。

  通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。

  数据结构按照其逻辑结构可分为线性结构、树结构、图结构:

    • 线性结构:数据结构中的元素存在一对一的相互关系
    • 树结构:数据结构中的元素存在一对多的相互关系
    • 图结构:数据结构中的元素存在多对多的相互关系

下面我来重点来学习数据结构中比较重要的几种:栈、队列、链表、哈希表、二叉搜索树

  栈(Stack)是一个数据集合,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。可以将栈理解为只能在一端进行插入或删除操作的列表。

  栈的特点:后进先出、先进后出(类似于往箱子里放东西,要拿的时候只能拿最上面的而最上面的是最后进的)

  栈操作:进栈push、出栈pop、取栈顶gettop(在Python中,不用自定义栈,直接用列表就行,进栈函数:append 出栈函数:pop 查看栈顶函数:li[-1])

栈的应用

  栈可以应用在处理括号匹配问题——括号匹配问题:给一个字符串,其中包含小括号、中括号、大括号,求该字符串中的括号是否匹配。

基本思路:按顺序遍历字符串是左括号则进栈,来的是右括号则将栈顶左括号pop,若来的右括号与栈顶左括号不匹配或空栈情况下来了右括号则返回错误信息

def brace_match(s):
stack = []
match = {')':'(', ']':'[', '}':'{'}
match2 = {'(':')', '[':']', '{':'}'}
for ch in s:
if ch in {'(', '[', '{'}:
stack.append(ch)#左括号入栈
elif len(stack) == 0:
print("缺少%s" % match[ch])#栈空了,但却来了一个右括号
return False
elif stack[-1] == match[ch]:#栈顶左括号与来的右括号相匹配
stack.pop()#出栈
else:
print("括号不匹配")
return False
if len(stack) > 0:#全部操作完后栈内还有剩余左括号
print("缺少%s" % (match2[stack[-1]]))#显示栈顶左括号对应的右括号
return False
print('合法')
return True brace_match("[{()[]}{}{}")#缺少]

队列

  队列(Queue)是一个数据集合,仅允许在列表的一端进行插入,另一端进行删除。 进行插入的一端称为队尾(rear),插入动作称为进队或入队;进行删除的一端称为队头(front),删除动作称为出队。和栈一样,队列是一种操作受限制的线性表。

  队列的性质:先进先出(可以将队列理解为排队买东西)

  特殊情况——双向队列:队列的两端都允许进行进队和出队操作。

如何用列表实现队列:

  1. 初步设想:列表+两个下标指针
  2. 创建一个列表和两个变量,front变量指向队首,rear变量指向队尾。初始时,front和rear都为0。
  3. 进队操作:元素写到li[rear]的位置,rear自增1。
  4. 出队操作:返回li[front]的元素,front自减1。

以上就是队列实现的基本思路,但是其实队列的实现原理是一个环形队列

环形队列:当队尾指针front == Maxsize + 1时,再前进一个位置就自动到0。

  • 实现方式:求余数运算
  • 队首指针前进1:front = (front + 1) % MaxSize
  • 队尾指针前进1:rear = (rear + 1) % MaxSize
  • 队空条件:rear == front
  • 队满条件:(rear + 1) % MaxSize == front

在Python中,有一个内置模块可以帮我们快速建立起一个队列——deque模块

"""
使用方法:from collections import deque
创建队列:queue = deque(li)
进队:append()
出队:popleft()
双向队列队首进队:appendleft()
双向队列队尾进队:pop()
"""

栈和队列的知识点应用:

  用栈和队列的知识来解决迷宫问题:http://www.cnblogs.com/zhuminghui/p/8414307.html

链表

  链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。
  每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
  使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。链表可以在多种编程语言中实现。像Lisp和Scheme这样的语言的内建数据类型中就包含了链表的存取和操作。程序语言或面向对象语言,如C,C++和Java依靠易变工具来生成链表。

  链表中每一个元素都是一个对象,每个对象称为一个节点,包含有数据域key和指向下一个节点的指针next。通过各个节点之间的相互连接,最终串联成一个链表。

#结点的定义
class Node(object):
def __init__(self, item):
self.item = item
self.next = None

  建立链表的方式有头插法和尾插法两种

  • 头插法:在一个结点的前面插入元素,head的指针由指向原来的结点变为指向新元素,新元素的指针指向原来的结点
  • 尾插法:在一个元素后面插入一个元素,原来结点的指针指向新元素

建立列表实现代码如下:

#定义结点
class Node:
def __init__(self, data):
self.data = data
self.next = None
#头插法
def create_linklist(li):
head = None
for num in li:
node = Node(num)
node.next = head
head = node
return head
#尾插法
def create_linklist_tail(li):
head = None
if not li:
return head
head = Node(li[0])
tail = head
for num in li[1:]:
node = Node(num)
tail.next = node
tail = node
return head def print_linklist(head):
node = head
while node:
print(node.data)
node = node.next linklist = create_linklist_tail([1,2,3,4])
print_linklist(linklist)
链表结点的插入
  链表插入结点的操作的重点是指针的变换,首先我们有两个结点A指向B,这时要在AB中间插入C,我们需要将C的指针指向B,然后将A的指针指向C,在删除AB之间的指针,就完成了C的插入,由AB变为了ACB
                

#curNode为A结点
c.next = curNode.next
curNode.next = c
链表结点的删除
  在链表中,要删除一个结点不能直接删掉就万事大吉,我们需要将指向该结点的结点的指针指向该结点指针指向的结点(A指向B指向C,B为要删除的该结点,将A的指针指向C),然后才能删除该节点(B)
                 

#p为要删除的结点
p = curNode.next
curNode.next = curNode.next.next#即p.next
del p
链表的特殊形态——双链表
  双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继(后面结点)和直接前驱(前面结点)。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。 
双向链表的节点定义:

class Node(object):
def __init__(self, item=None):
self.item = item
self.next = None
self.prior = None

双向链表结点的插入

  与链表相同,双向链表插入结点也需要将指针进行变换。同样是AB之间要插入C,我们需要先将C的指针指向B、B的指针由指向A转变为指向B,然后C的另一个指针指向A,A结点的指针由指向B转变为指向B。
    
#p为新插入的元素
p.next = curNode.next
curNode.next.prior = p
p.prior = curNode
curNode.next = p
双向链表结点的删除
  删除双向链表的结点前需要建立起该结点前后两个结点的指针关系,然后才能删除结点
#p为要删除的结点
p = curNode.next
curNode.next = p.next
p.next.prior = curNode
del p
链表的复杂度分析
  • 按元素值查找——O(n),因为没有下标所以没法做二分
  • 按下标查找——O(n),因为没有下标
  • 在某元素后插入——O(1)
  • 删除某元素——O(1)
 
哈希表 

  哈希表(Hash Table,又称为散列表),是一种线性表的存储结构。哈希表由一个顺序表(数组)和一个哈希函数组成。哈希函数h(k)将元素k作为自变量,返回元素的存储下标。

  假设有一个长度为7的数组,哈希函数h(k)=k%7。元素集合{14,22,3,5}的存储方式如下图。

哈希冲突:

  由于哈希表的大小是有限的,而要存储的值的总数量是无限的,因此对于任何哈希函数,都会出现两个不同元素映射到同一个位置上的情况,这种情况叫做哈希冲突。

比如上图中的哈希表就存在这哈希冲突——h(k)=k%7, h(0)=h(7)=h(14)=...

解决哈希冲突方法
方法一:开放寻址法——如果哈希函数返回的位置已经有值,则可以向后探查新的位置来存储这个值。

  • 线性探查:如果位置i被占用,则探查i+1, i+2,……
  • 二次探查:如果位置i被占用,则探查i+12,i-12,i+22,i-22,……
  • 二度哈希:有n个哈希函数,当使用第1个哈希函数h1发生冲突时,则尝试使用h2,h3,……

方法二:拉链法——哈希表每个位置都连接一个链表,当冲突发生时,冲突的元素将被加到该位置链表的最后。

哈希表在Python中的应用

#字典与集合都是通过哈希表来实现的
#在Python中的字典:
a = {'name': 'Damon', 'age': 18, 'gender': 'Man'}
#使用哈希表存储字典,通过哈希函数将字典的键映射为下标。假设h(‘name’) = 3, h(‘age’) = 1, h(‘gender’) = 4,则哈希表存储为[None, 18, None, ’Damon’, ‘Man’]
#在字典键值对数量不多的情况下,几乎不会发生哈希冲突,此时查找一个元素的时间复杂度为O(1)。
二叉搜索树 
  二叉搜索树知识点地址:http://www.cnblogs.com/zhuminghui/p/8409508.html
 
 
 
 
 
 
                           

what's the 数据结构的更多相关文章

  1. 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

  2. 一起学 Java(三) 集合框架、数据结构、泛型

    一.Java 集合框架 集合框架是一个用来代表和操纵集合的统一架构.所有的集合框架都包含如下内容: 接口:是代表集合的抽象数据类型.接口允许集合独立操纵其代表的细节.在面向对象的语言,接口通常形成一个 ...

  3. 深入浅出Redis-redis底层数据结构(上)

    1.概述 相信使用过Redis 的各位同学都很清楚,Redis 是一个基于键值对(key-value)的分布式存储系统,与Memcached类似,却优于Memcached的一个高性能的key-valu ...

  4. 算法与数据结构(十五) 归并排序(Swift 3.0版)

    上篇博客我们主要聊了堆排序的相关内容,本篇博客,我们就来聊一下归并排序的相关内容.归并排序主要用了分治法的思想,在归并排序中,将我们需要排序的数组进行拆分,将其拆分的足够小.当拆分的数组中只有一个元素 ...

  5. 算法与数据结构(十三) 冒泡排序、插入排序、希尔排序、选择排序(Swift3.0版)

    本篇博客中的代码实现依然采用Swift3.0来实现.在前几篇博客连续的介绍了关于查找的相关内容, 大约包括线性数据结构的顺序查找.折半查找.插值查找.Fibonacci查找,还包括数结构的二叉排序树以 ...

  6. 算法与数据结构(九) 查找表的顺序查找、折半查找、插值查找以及Fibonacci查找

    今天这篇博客就聊聊几种常见的查找算法,当然本篇博客只是涉及了部分查找算法,接下来的几篇博客中都将会介绍关于查找的相关内容.本篇博客主要介绍查找表的顺序查找.折半查找.插值查找以及Fibonacci查找 ...

  7. 算法与数据结构(八) AOV网的关键路径

    上篇博客我们介绍了AOV网的拓扑序列,请参考<数据结构(七) AOV网的拓扑排序(Swift面向对象版)>.拓扑序列中包括项目的每个结点,沿着拓扑序列将项目进行下去是肯定可以将项目完成的, ...

  8. 算法与数据结构(七) AOV网的拓扑排序

    今天博客的内容依然与图有关,今天博客的主题是关于拓扑排序的.拓扑排序是基于AOV网的,关于AOV网的概念,我想引用下方这句话来介绍: AOV网:在现代化管理中,人们常用有向图来描述和分析一项工程的计划 ...

  9. 掌握javascript中的最基础数据结构-----数组

    这是一篇<数据结构与算法javascript描述>的读书笔记.主要梳理了关于数组的知识.部分内容及源码来自原作. 书中第一章介绍了如何配置javascript运行环境:javascript ...

  10. [数据结构]——链表(list)、队列(queue)和栈(stack)

    在前面几篇博文中曾经提到链表(list).队列(queue)和(stack),为了更加系统化,这里统一介绍着三种数据结构及相应实现. 1)链表 首先回想一下基本的数据类型,当需要存储多个相同类型的数据 ...

随机推荐

  1. vector的多套遍历方案

    1.迭代器 begin,end,*it++ 2.下标法 3.at函数(GetAt) 4.指针法 指针移到头部rewind.

  2. ASP.NET MVC 4 (六) 帮助函数

    帮助函数封装一些代码,方便我们在应用程序中重用,MVC内建很多帮助函数,可以很方便的生成HTML标记.首先列出后面示例中用到的数据模型类定义: namespace HelperMethods.Mode ...

  3. SpringBoot Docker入门,SpringBoot Docker安装

    SpringBoot Docker入门,SpringBoot Docker安装 ================================ ©Copyright 蕃薯耀 2018年4月8日 ht ...

  4. Mariadb 10.3.5 序列号(sequence) 尝鲜

    除了Oracle Mariadb 也有sequence了,前提是Mariadb 10.3以上版本才支持. 但目前的正式版依然是10.2 启动一个Mariadb 10.3.5 docker pull m ...

  5. Scala中的协变,逆变,上界,下界等

    Scala中的协变,逆变,上界,下界等 目录 [−] Java中的协变和逆变 Scala的协变 Scala的逆变 下界lower bounds 上界upper bounds 综合协变,逆变,上界,下界 ...

  6. MVC和普通三层架构的区别

    MVC和普通三层架构的区别 其中这里的模型(Model)和视图(View )是完全区别于三层架构中的模型(Model)和视图(View)的. MVC 1)MVC中的模型(Model)指的是数据模型,用 ...

  7. WCF中序列化(XML\JSON\Dt)

    序列化 是将对象转换为容易传输的格式的过程.例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象.反之,反序列化根据流重新构造对象. 序列化描述了持久化 ...

  8. pandas pivot_table 活学活用实例教程

    pandas pivot_table 活学活用实例教程 导入相关数据分析的库 首先进行commentTime时间进行数据预处理 查看数据类型信息 最简单的透视表 直接敲击该函数,在notebook中可 ...

  9. 10.10xadmin

    2018-10-10 15:11:55 这几天讲的是xadmin插件 就是把表单,数据内容封装到类里面,简化的增删改查步骤! 放上源代码: app01/xadim.py from django.con ...

  10. nodejs 获取自己的ip

    代码片段 // npm i --save-dev request const request = require('request'); const url = "http://ip.tao ...