数据结构--栈、队列、链表、树

线性数据结构:数组、链表、栈、队列

非线性结构:集合、树形结构、图状结构

数据结构之线性结构和非线性结构_HOLD ON!的博客-CSDN博客_数据结构的线性结构和非线性结构

一、栈


1、检查符号是否成对出现

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断该字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

比如 "()"、"()[]{}"、"{[]}" 都是有效字符串,而 "(]" 、"([)]" 则不是。

代码:

//检查符号是否成对出现
/*只要遇见右括号就比较栈顶是否是他的对应括号:之前匹配的也都全出栈了*/
private boolean isValid(String s) {
    HashMap<Character,Character> map=new HashMap<>();
    map.put(')','(');
    map.put('}','{');
    map.put(']','[');
    Stack<Character> stack=new Stack<>();
    char[] chars=s.toCharArray();
    for (char ch:chars){
        if (map.containsKey(ch)){
            char element=stack.pop();//配对就出栈啦,不配对就返回false
            if (element!=map.get(ch)){
                return false;
            }
        }else {
            stack.push(ch);
        }
    }
    return stack.empty();
    }

二、队列


1、单队列

2、循环队列

队列初始:rear=0,font=0,font指向第一个元素,rear指向最后一个元素的下一个

队列空:rear=font

队列满:(rear+1)%maxSize==font

队列元素个数:(rear-font+maxSize)%maxSize

遍历队列:

for (int i=font;i<font+((rear-font+maxSize)%maxSize);i++){
    System.out.printf("arr[%d]=%d\n",i%maxSize,arr[i%maxSize]);
}

3、应用场景 *

  • 阻塞队列: 阻塞队列可以看成在队列基础上加了阻塞操作的队列。当队列为空的时候,出队操作阻塞,当队列满的时候,入队操作阻塞。使用阻塞队列我们可以很容易实现“生产者 - 消费者“模型。
  • 线程池中的请求/任务队列: 线程池中没有空闲线程时,新的任务请求线程资源时,线程池该如何处理呢?答案是将这些请求放在队列中,当有空闲线程的时候,会循环中反复从队列中获取任务来执行。队列分为无界队列(基于链表)和有界队列(基于数组)。无界队列的特点就是可以一直入列,除非系统资源耗尽,比如 :FixedThreadPool 使用无界队列 LinkedBlockingQueue。但是有界队列就不一样了,当队列满的话后面再有任务/请求就会拒绝,在 Java 中的体现就是会抛出java.util.concurrent.RejectedExecutionException 异常。
  • Linux 内核进程队列(按优先级排队)
  • 现实生活中的派对,播放器上的播放列表;
  • 消息队列
  • 等等......

三、单链表


链表的插入和删除操作的复杂度为 O(1) ,只需要知道目标位置元素的上一个元素即可。但是,在查找一个节点或者访问特定位置的节点的时候复杂度为 O(n) 。

常见链表分类:

  1. 单链表
  2. 双向链表
  3. 循环链表
  4. 双向循环链表


数组 vs 链表

  • 数组支持随机访问,而链表不支持。
  • 数组使用的是连续内存空间对 CPU 的缓存机制友好,链表则相反。
  • 数组的大小固定,而链表则天然支持动态扩容。如果声明的数组过小,需要另外申请一个更大的内存空间存放数组元素,然后将原数组拷贝进去,这个操作是比较耗时的!

四、树


树 | JavaGuide

1、树的概念

树就是一种类似现实生活中的树的数据结构。任何一颗非空树只有一个根节点

一棵树具有以下特点:

  1. 一棵树的任意两个结点有且仅有唯一的一条路径联通
  2. 一棵树如果有n个结点,那么它一定恰好有n-1条边
  3. 一棵树不包含回路

2、二叉树

什么是二叉树?

二叉树是树的一种类型,每个节点最多只有两个分支的树结构。二叉树的分支通常被称作左子树或右子树。二叉树的分支具有左右次序,不能随意颠倒。

二叉树相关计算:

  • 二叉树的第i层至多拥有2(i-1) 个节点
  • 深度为k的二叉树至多总共有2(k+1)-1个节点,至少有2k个节点
  • n0=n2+1
  • 具有n个节点的完全二叉树深度为|log2n|+1

3、满二叉树

一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是 满二叉树。也就是说,如果一个二叉树的层数为 K,且结点总数是(2^k) -1 ,则它就是 满二叉树

4、完全二叉树

除最后一层外,若其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干节点,则这个二叉树就是 完全二叉树

完全二叉树的特性:

当根节点的值为 1 的情况下,若父结点的序号是 i,那么左子节点的序号就是 2i,右子节点的序号是 2i+1。

5、平衡二叉树

斜树

改进-平衡二叉树

平衡二叉树是一颗二叉排序数,具有以下性质:

  1. 可以是一课空树
  2. 如果不是空树,它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一个平衡二叉树。

平衡二叉树的常用实现方法有红黑树、AVL树、替罪羊树、加权平衡树、伸展树

6、二叉树的存储

二叉树的存储主要分为链式存储顺序存储两种:

链式存储

和链表类似,二叉树的链式存储依靠指针将各个节点串联起来,不需要连续的存储空间。

每个节点包括三个属性:

  • 数据data。data不一定是单一的数据,根据不同情况,可以是多个具有不同类型的数据
  • 左节点指针left
  • 右节点指针right

Java中用引用对象

指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元,即指针是一个实体;而引用跟原来的变量实质上是一个东西,只不过是原变量的一个别名而已

顺序存储

顺序存储就是利用数组进行存储,数组中的每一个位置仅存储节点的data,不存储左右子节点的指针,子节点的索引通过数组下标完成。根节点的序号为1,对于每个节点Node,假设它存储在数组中下标为i的位置,那么它的左子节点就存储在2i的位置,右子节点存储在下标在2i+1的位置

一课完全二叉树的数组顺序存储如下图;

如果不是完全二叉树,存储会出现数组空隙,导致内存利用率低

7、二叉树的遍历

1)先序遍历

顺序;

  • 根节点
  • 左子树
  • 右子树

代码:

public void preOrder(TreeNode root){
    if (root==null){
        return;
    }
    System.out.println(root.data);
    preOrder(root.left);
    preOrder(root.right);
}

2)中序遍历

顺序:

  • 左子树
  • 根节点
  • 右子树

代码:

public void inOrder(TreeNode root){
    if (root==null){
        return;
    }
    preOrder(root.left);
    System.out.println(root.data);
    preOrder(root.right);
}

3)后序遍历

顺序:

  • 左子树
  • 右子树
  • 根节点

代码:

public void postOrder(TreeNode root){
    if (root==null){
        return;
    }
    preOrder(root.left);
    preOrder(root.right);
    System.out.println(root.data);
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值