数据结构详解

概述

数据结构(data structure)是带有结构特性的数据元素的集合,它研究的是数据的逻辑结构和数据的物理结构以及它们之间的相互关系,并对这种结构定义相适应的运算,设计出相应的算法,并确保经过这些运算以后所得到的新结构仍保持原来的结构类型。简而言之,数据结构是相互之间存在一种或多种特定关系的数据元素的集合,即带“结构”的数据元素的集合。“结构”就是指数据元素之间存在的关系,分为逻辑结构和存储结构。

数据的逻辑结构和物理结构是数据结构的两个密切相关的方面,同一逻辑结构可以对应不同的存储结构。算法的设计取决于数据的逻辑结构,而算法的实现依赖于指定的存储结构

数据结构的研究内容是构造复杂软件系统的基础,它的核心技术是分解与抽象。通过分解可以划分出数据的3个层次;再通过抽象,舍弃数据元素的具体内容,就得到逻辑结构。类似地,通过分解将处理要求划分成各种功能,再通过抽象舍弃实现细节,就得到运算的定义。上述两个方面的结合可以将问题变换为数据结构。这是一个从具体(即具体问题)到抽象(即数据结构)的过程。然后,通过增加对实现细节的考虑进一步得到存储结构和实现运算,从而完成设计任务。这是一个从抽象(即数据结构)到具体(即具体实现)的过程。

简而言之数据结构是——以某种特定的布局方式存储数据
这种“布局方式”决定了数据结构对于某些操作是高效的,而对于其他操作则是低效的。首先我们需要理解各种数据结构,才能在处理实际问题时选取最合适的数据结构。

数据结构分类

  • [1、数组]
  • [2、栈]
  • [3、队列]
  • [4、链表]
  • [5、树]
  • [6、散列表]
  • [7、堆]
  • [8、图]

数据结构详解_第1张图片
每一种数据结构都有着独特的数据存储方式

1、数组(Array):
数组是最简单、也是使用最广泛的数据结构。栈、队列等其他数据结构均由数组演变而来。每个数据元素都关联一个正数值,我们称之为索引,它表明数组中每个元素所在的位置。大部分语言将初始索引定义为零。
数组是可以再内存中连续存储多个元素的结构,在内存中的分配也是连续的,数组中的元素通过数组下标进行访问,数组下标从0开始,例如下面这段代码就是将数组的第一个元素赋值为 1
image.png

优点:
1、按照索引查询元素速度快
2、按照索引遍历数组方便

缺点:
1、数组的大小固定后就无法扩容了
2、数组只能存储一种类型的数据
3、添加,删除的操作慢,因为要移动其他的元素。


一维数组 --- int[] a = new int [4];
-------- 数组也是一个变量,是存储一组相同类型的变量
数据结构详解_第2张图片

声明一个变量就是在内存中划出一块合适的空间

声明一个数组就是在内存中划出一块连续的空间


二维数组 ---int [] [] arr = new int[3] [4];

3表示这个二维数组有3个一维数组,名称是arr[0],arr[1],arr[2],4表示每一个一维数组有4个元素。
数据结构详解_第3张图片

数据结构详解_第4张图片

2、栈(Stack)
数据结构详解_第5张图片

栈是一种只能在尾部进行插入或删除的线性表。其中,允许插入或删除的一端称为栈顶(Top),是变化的,另一端称为栈底,是固定不变的。栈的插入操作称为入栈/进栈/压栈。栈的删除操作称为出栈/退栈。

栈的特点是:先进后出,或者说是后进先出。

数据结构详解_第6张图片
栈的基本操作:
new Stack();
Push——在顶部插入一个元素
Pop——返回并移除栈顶元素
isEmpty——如果栈为空true
Top——返回顶部元素,但并不移除它

3、队列(Queue)
队列是一种比较特殊的线性结构。它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中最先插入的元素也将最先被删除,对应的最后插入的元素将最后被删除。因此队列又称为“先进先出”(FIFO—first in first out)的线性表,与栈(FILO-first in last out)刚好相反。从一端放入元素的操作称为入队,取出元素为出队,示例图如下:

队列现实例子:售票亭排队队伍。如果有新人加入,他需要到队尾去排队,而非队首——排在前面的人会先拿到票,然后离开队伍。
右图是包含三个元素(A,B,C)的队列,其中在头部(front)的A将被最先移除。
移除先入队的元素、插入新元素适用场景。

使用场景:
因为队列先进先出的特点,在多线程阻塞队列管理中非常适用。(例如:优先级队列)。

数据结构详解_第7张图片
*解决“假溢出”,可以用循环列队

数据结构详解_第8张图片

通过两个堆栈实现一个队列:
栈的结构是先进后出,队列的结构是先进先出,那么用两个栈模拟一个队列的思路b就是一个栈用来入列,另一个栈用来出列。

数据结构详解_第9张图片

1)入列:依次往stack1中插入a、b、c
2)出列:若stack2为空的话,那么stack1中元素依次出栈,压入stack2中,此时stack2中的元素从栈顶往栈底方向依次是c、b、a,然后依次弹出元素a和b
3)入列:往stack1中插入d元素
4)出列:此时stack2中依然有元素c,那么c比d先入列,则c应该比d先出列,所以此时出列元素为c
5)出列:此时stack2中没有元素,那么stack1中有元素d出栈压入stack2,stack2中的元素d弹出(即出列)

数据结构详解_第10张图片
队列实现的三种方式:
(1)通过数组实现一个队列;
(2)通过集合实现一个对列;JDK中,LinkedList类实现了Queue接口,可以当Queue使用。
(3)通过两个堆栈实现一个队列。

队列的基本操作:
push()-——在栈顶增加元素
pop()-——在栈顶移除元素
Enqueue()——在队列尾部插入元素Dequeue()——移除队列头部的元素isEmpty()——如果队列为空,则返回trueTop()——返回队列的第一个元素

4、链表(Linked list)
链表是物理存储单元上非连续的、非顺序的存储结构,乍一看可能有点像数组,但在内存分配、内部结构以及数据插入和删除的基本操作方面均有所不同。链表就像一个节点链,其中每个节点包含着数据和指向后续节点的指针。链表还包含一个头指针,它指向链表的第一个元素,但当列表为空时,它指向null或无具体内容。

数据结构详解_第11张图片
**单链表:如果访问任意结点每次只能从头开始顺序向后访问
单循链表:可以从任何一个结点开始,顺序向后访问到达任意结点
双向链表:可以从任何结点开始任意向前向后双向访问**

链表的优点:
链表是很常用的一种数据结构,不需要初始化容量,可以任意加减元素;
添加或者删除元素时只需要改变前后两个元素结点的指针域指向地址即可,所以添加,删除很快;

缺点:
因为含有大量的指针域,占用空间较大;
查找元素需要遍历链表来查找,非常耗时。
适用场景:
数据量较小,需要频繁增加,删除操作的场景,一般用于实现文件系统、哈希表和邻接表。

数据结构详解_第12张图片

5.图(graph)
表示多对多的关系。
图是由结点的有穷集合V和边的集合E组成。其中,为了与树形结构加以区别,在图结构中常常将结点称为顶点,边是顶点的有序偶对,若两个顶点之间存在一条边,就表示这两个顶点具有相邻关系。

图是一种比较复杂的数据结构,在存储数据上有着比较复杂和高效的算法,分别有邻接矩阵 、邻接表、十字链表、邻接多重表、边集数组等存储结构。
数据结构详解_第13张图片
数据结构详解_第14张图片
数据结构详解_第15张图片
就像一个站可以连接多个地铁站

数据结构详解_第16张图片

数据结构详解_第17张图片

图的表示方法有两种:二维数组表示(邻接矩阵);链表表示(邻接表)
数据结构详解_第18张图片
数据结构详解_第19张图片
1,邻接矩阵需要为每个顶点都分配n个边的空间,其实有很多边是不存在的,会造成空间损失。
2,邻接表只关心存在的边,不关心不存在的边,因此没有空间浪费,邻接表由数组+链表组成。

6.树(Tree)
因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:

  • 每个节点有零个或多个子节点;
  • 没有父节点的节点称为根节点;
  • 每一个非根节点有且只有一个父节点;
  • 除了根节点外,每个子节点可以分为多个不相交的子树;

使用场景:树形结构被广泛应用于人工智能和复杂算法,它可以提供解决问题的有效存储机制。

数据结构详解_第20张图片

树的相关概念术语:
数据结构详解_第21张图片
数据结构详解_第22张图片

以下是树形结构的主要类型:

  • N元树
  • 平衡树
  • 二叉树
  • 二叉搜索树
  • AVL树
  • 红黑树
  • 2-3树

其中,二叉树和二叉搜索树是最常用的树。

/**
 * 创建一个树结构:
 *
 *           李磊
 *        |         |
 *    韩梅梅       丽丽
 *                   |
 *                 李刚
 */
public class TreeNode {    
        private int age;    // 节点属性,年龄
        private String name;   //节点属性,姓名

        TreeNode proTreeNode;    //上级节点
        List list = new ArrayList(); //孩子节点

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public TreeNode getProTreeNode() {
            return proTreeNode;
        }

        public void setProTreeNode(TreeNode proTreeNode) {
            this.proTreeNode = proTreeNode;
        }

        public void addTreeNode(TreeNode treeNode){
            list.add(treeNode);
            treeNode.proTreeNode = this;
        }
            public TreeNode getTreeNode(Integer i){
            return list.get(i);
        }

        public void removeTreeNode(TreeNode treeNode){
            list.remove(treeNode);
            treeNode.proTreeNode = null;
        }

        public String toString(){
            return "姓名:"+name+";年龄:"+age+"。";
        }
    
    public static void main(String[] args) {
        TreeNode treeNode0 = new TreeNode();
        treeNode0.setAge(11);
        treeNode0.setName("李磊");

        TreeNode treeNode1 = new TreeNode();
        treeNode1.setAge(13);
        treeNode1.setName("韩梅梅");

        TreeNode treeNode2 = new TreeNode();
        treeNode2.setAge(15);
        treeNode2.setName("丽丽");

        TreeNode treeNode3 = new TreeNode();
        treeNode3.setAge(15);
        treeNode3.setName("李刚");

        treeNode0.addTreeNode(treeNode1); //父节点关联孩子节点
        treeNode0.addTreeNode(treeNode2); //父节点关联孩子节点

        treeNode2.addTreeNode(treeNode3); //丽丽节点下挂李刚

        System.out.println(treeNode1+"======本身节点");   //打印节点本身
        System.out.println(treeNode2.getTreeNode(0)+"======打印树节点");  //打印树节点
        System.out.println(treeNode1.getProTreeNode()+"======打印父接口");  //打印父接口
    }       
    }

数据结构详解_第23张图片

7.散列表/哈希表(Hashing)

哈希表也叫散列表,是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度,这个映射函数叫做散列函数,存放记录的数组叫做散列表。

记录的存储位置=f(key)

而当使用哈希表进行查询的时候,就是再次使用哈希函数将key转换为对应的数组下标,并定位到该空间获取value,如此一来,就可以充分利用到数组的定位性能进行数据定位。
数据结构详解_第24张图片

Hash的应用:

1、Hash主要用于信息安全领域中加密算法,它把一些不同长度的信息转化成杂乱的128位的编码,这些编码值叫做Hash值. 也可以说,Hash就是找到一种数据内容和数据存放地址之间的映射关系。
2、Hash表在海量数据处理中有着广泛应用。

数据结构详解_第25张图片
从图中可以看出,左边很明显是个数组,数组的每个成员包括一个指针,指向一个链表的头,当然这个链表可能为空,也可能元素很多。我们根据元素的一些特征把元素分配到不同的链表中去,也是根据这些特征,找到正确的链表,再从链表中找出这个元素。

哈希表的应用场景很多,当然也有很多问题要考虑,比如哈希冲突的问题,如果处理的不好会浪费大量的时间,导致应用崩溃。

8.堆(heap)

堆是一种比较特殊的数据结构,可以被看做一棵树的数组对象,具有以下的性质:

堆中某个节点的值总是不大于或不小于其父节点的值;

堆总是一棵完全二叉树。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。

因为堆有序的特点,一般用来做数组中的排序,称为堆排序
数据结构详解_第26张图片

数据结构详解_第27张图片

数据的逻辑结构

数据结构详解_第28张图片

你可能感兴趣的:(java数据结构后端)