常见数据结构-栈-队列-数组-链表-哈希表

数据结构

  数据结构是计算机存储、组织数据的方式。是指相互之间存在一种或多种特定关系的数据元素的集合
  通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率

持续更新,学一个记一个~

栈模型:

    一端开口 ==栈顶==
    
|                    |
|                    |
|                    |
|                    |
|                    |
|____________________|
    一端封闭 ==栈底==
  • 数据进入栈模型的过程称为:压/进栈

|                    |                 |                    |
|                    |    [数据 A]      |     [数据 D]       | <- 栈顶元素
|                    |    [数据 B]      |     [数据 C]       |
|                    |    [数据 C]      |     [数据 B]       |
|                    |    [数据 D]      |     [数据 A]       | <- 栈底元素
|____________________|                 |____________________|
  • 数据离开栈模型的过程称为:弹/出栈
    出栈顺序为从栈顶元素到栈底元素

栈是一种先进后出的模型

队列

队列模型:

    一端开口 ==后端==
    
|                    |
|                    |
|                    |
|                    |
|                    |
|                    |
    一端开头 ==前端==
  • 数据从后端进入队列模型的过程称为:入队列

|                    |                 
|                    |    [数据 A]      
|                    |    [数据 B]      
|                    |    [数据 C]      
|                    |    [数据 D]      
|                    |  

----------------------------------------------------------               

       入队列方向
          \|/    后端
|                   |
|     [数据 D]       | 
|     [数据 C]       |
|     [数据 B]       |
|     [数据 A]       | 
|                   |
         \|/     前端
       出队列方向
  • 数据从前端离开队列模型的过程称为:出队列

队列是一种先进先出的模型

数组

数组模型:


___0___1___2___3___4___5___6___
| [A] [B] [C] [D] [E] [F] [G] |
|_____________________________|
  • 查询数据通过索引定位,查询任意数据耗时相同,查询数度快
  • 删除数据时,要将原始数据删除,同时后面每个数据前移,删除效率低
  • 添加数据时,添加位置后的每个数据后移,再添加元素,添加效率极低

数组是一种查询快,增删慢的模型

链表

链表的每一个元素被称为结点

结点模型:

 [地址1]
________________
| [数据] [地址2] |
|_______________|

-----------------------------------------
地址1:结点的==存储位置(地址)==
数据:存储具体的==数据==
地址2:下一个结点的==地址==

头结点模型:

______________
| [head] [^] |
|____________|
-----------------------------------------
^:结点指向==空地址(表示结束)==

链表模型链接过程示例

  1. 给头结点存储一个数据A,保存在地址11的位置:
                     [11]
_______________      ___________
| [head] [11] | -->  | [A] [^] |
|_____________|      |_________|

  1. 再存储一个数据C,保存在地址37位置
                     [11]             [37]
_______________      ____________     ___________
| [head] [11] | -->  | [A] [37] | --> | [C] [^] |
|_____________|      |__________|     |_________|

  1. 再存储一个数据D,保存在地址96位置
                     [11]             [37]             [96]
_______________      ____________     ____________     ____________
| [head] [11] | -->  | [A] [37] | --> | [C] [96] | --> | [D]  [^] |
|_____________|      |__________|     |__________|     |__________|

链表模型添加数据过程示例

在数据AC之间添加一个数据B,保存在地址54地址

                     [11]             [37]             [96]
_______________      ____________     ____________     ____________
| [head] [11] | -->  | [A] [37] | --> | [C] [96] | --> | [D]  [^] |
|_____________|      |__________|     |__________|     |__________|

                                       [54]
                                      ___________
                                      | [B] [^] |
                                      |_________|
  1. 数据B对应的下一个数据地址指向数据C
                     [11]             [37]             [96]
_______________      ____________     ____________     ____________
| [head] [11] | -->  | [A] [37] | --> | [C] [96] | --> | [D]  [^] |
|_____________|      |__________|     |__________|     |__________|
                                        &uarr;
                                       [54]
                                      ____________
                                      | [B] [37] |
                                      |__________|
  1. 数据A对应的下一个数据地址指向数据B
                     [11]             [37]             [96]
_______________      ____________     ____________     ____________
| [head] [11] | -->  | [A] [54] |     | [C] [96] | --> | [D]  [^] |
|_____________|      |__________|     |__________|     |__________|
                           |            &uarr;
                           |           [54]
                           |          ____________
                           |--------> | [B] [37] |
                                      |__________|

链表模型删除数据过程示例

删除数据BD之间的数据C

                     [11]             [37]             [96]
_______________      ____________     ____________     ____________
| [head] [11] | -->  | [A] [54] |     | [C] [96] | --> | [D]  [^] |
|_____________|      |__________|     |__________|     |__________|
                           |            &uarr;
                           |           [54]
                           |          ____________
                           |--------> | [B] [37] |
                                      |__________|
  1. 数据B对应的下一个数据地址指向数据D
                     [11]             [37]             [96]
_______________      ____________     ____________     ____________
| [head] [11] | -->  | [A] [54] |     | [C] [96] | --> | [D]  [^] |
|_____________|      |__________|     |__________|     |__________|
                           |                             &uarr;
                           |           [54]              |
                           |          ____________       |
                           |--------> | [B] [96] |-------|
                                      |__________|
  1. 数据C删除
                     [11]                              [96]
_______________      ____________                      ____________
| [head] [11] | -->  | [A] [54] |                      | [D]  [^] |
|_____________|      |__________|                      |__________|
                           |                             &uarr;
                           |           [54]              |
                           |          ____________       |
                           |--------> | [B] [96] |-------|
                                      |__________|
  • 查询数据D是否存在,必须从头(head)开始查询
  • 查询第n个数据,也必须从头(head)开始查询

链表是一种增删快,查询慢的模型(对比数组)

哈希表

JDK 8 之前,底层采用数据+链表实现,可以说是一个元素为链表的数组

JDK 8 以后,在长度比较长的时候,底层实现了优化

哈希表存储元素示例(如何保证元素唯一性)

  待存储元素为:

“hello”
“world”
“java”
“world”
“通信”
“软件”

  为了方便演示,计算各元素的哈希值为(实际计算机操作是每一次添加都进行独立计算):

“hello” ---- 99162322
“world” ---- 113318802
“java” ---- 3254818
“world” ---- 113318802
“通信” ---- 1179395
“软件” ---- 1179395

  在JDK说明文档中看到HashSet的空参构造方法的描述为:

HashSet():构造一个空的集合;支持HashMap实例具有默认初始容量(16)和加载因子(0.75)。


  对于这个加载因子为什么是0.75我在晚上查阅了很多资料,大部分说它是与泊松分布直接相关,直到后面我又看到一篇反驳的博客,链接都放在这里了,对学术研究还是要保持好奇,保持质疑的精神啊
  支持与泊松分布直接相关
  反驳


  据此我们得到HashSet的模型:

  [0]  [1]  [2]  [3]  [4]  [5]  [6]  [7]  [8]  [9] [10] [11] [12] [13] [14] [15]      
_________________________________________________________________________________
|    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |
|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|

  那么如何存储各元素的哈希值到哈希表中呢?

  将各元素的哈希值进行对16取余,余数是几就存储到几中

“hello” ---- 99162322 % 16 =>   2
“world” ---- 113318802 % 16 =>  2
“java” ---- 3254818 % 16 =>     2
“world” ---- 113318802 % 16 =>  2
“通信” ---- 1179395 % 16 =>      3
“软件” ---- 1179395 % 16 =>      3

  显然我们只需要用到编号为2的位置和编号为3的位置,所以下面的演示省略未用到的部分(实际没用到也是存在的)

             [2]          [3] 
        ___________________________
.....   |            |            |    .....
        |____________|____________|
  1. 尝试添加“hello”

  根据“hello”的哈希值计算出它的存储位置是2,此时2号位没有元素,所以直接添加元素:

     [2]          [3] 
___________________________
|   “hello”   |            |
|_____________|____________|
  1. 尝试添加“world”

  根据“world”的哈希值计算出它的存储位置也是2,此时2号位已经有元素,所以需要和已存在的元素进行比较,首先比较哈希值:

99162322   !=   113318802
“hello”          “world” 

  第一步对比发现二者哈希值不同,所以直接添加元素,元素也存储在2号位,但是是以链表的形式存储:

     [2]          [3] 
___________________________
|   “hello”   |            |
|______|______|____________|
       &uarr;
  ___________
  | “world” |
  |_________|
  1. 尝试添加“java”   同第二步,比较待添加元素和已存在所有元素的哈希值
99162322   !=    3254818
“hello”          “java” 
---------------------------
113318802   !=   3254818
“world”          “java” 

  依次比较所有已存在元素后发现哈希值均不同,所以直接添加元素,同样以链表的形式存储在2号位:

     [2]          [3] 
___________________________
|   “hello”   |            |
|______|______|____________|
       &uarr;
  ___________
  | “world” |
  |_________|
       &uarr;
  ___________
  | “java”  |
  |_________|
  1. 尝试添加“world”

  同第二步,比较待添加元素和已存在所有元素的哈希值

99162322   !=    113318802
“hello”          “world” 
---------------------------
113318802   ==   113318802
“world”          “world” 
---------------------------
3254818   !=   113318802
“java”          “world” 

  依次比较所有已存在元素后发现哈希值存在相同值,所以继续比较相同哈希值的元素内容是否相同:

113318802   ==   113318802
 “world”    ==    “world” 

  比较后发现内容一致,故跳过添加操作

  1. 尝试添加“通信”

  根据“通信”的哈希值计算出它的存储位置是3,此时3号位没有元素,所以直接添加元素:

     [2]          [3] 
____________________________
|   “hello”   |   “通信”    |
|______|______|____________|
       &uarr;
  ___________
  | “world” |
  |_________|
       &uarr;
  ___________
  | “java”  |
  |_________|
  1. 尝试添加“软件”

  根据“软件”的哈希值计算出它的存储位置也是3,此时3号位已经有元素,所以需要和已存在的元素进行比较,首先比较哈希值:

 1179395   ==   1179395
  “通信”         “软件” 

  比较后发现二者哈希值相同,所以继续比较元素内容是否相同:

 1179395   ==   1179395
  “通信”   !=    “软件” 

  发现内容并不相同,故以链表的形式添加元素:

     [2]          [3] 
____________________________
|   “hello”   |   “通信”    |
|______|______|_____|______|
       &uarr;            &uarr;
  ___________   __________
  | “world” |   | “软件” |
  |_________|   |_______|
       &uarr;
  ___________
  | “java”  |
  |_________|

  至此,哈希表添加元素操作演示完毕

猜你喜欢

转载自blog.csdn.net/m0_46700215/article/details/121377082