数据结构与算法回顾-1:算法的度量和基本数据结构

本文介绍了Java中的链表(单链表、双向链表、静态链表)、栈和队列的定义、操作及其实现,包括插入、删除、查找等,并探讨了树和二叉树的概念、遍历方法,以及它们在实际问题中的应用场景。
摘要由CSDN通过智能技术生成

public class LinkedList {

transient int size = 0;

transient Node first;

private static class Node {

E item;

Node next;

Node(E element, Node next) {

this.item = element;

this.next = next;

}

}

}

这里使用泛型的来代表链表的每个节点中存储的数据,使用内部类 Node 类定义链表的一个节点。

3.2.2 单链表的操作
  1. 每次建立链表时将结点插入到头部:建立一个长度为n的链表的时间复杂度是 O(n)

  2. 每次建立链表时将结点插入到尾部:建立一个长度为n的链表的时间复杂度是 O(n)

  3. 插值节点:从头结点出发,顺着 next 指针往下找,时间复杂度为 O(n)

  4. 按值查找表结点:时间复杂度为 O(n)

  5. 插入和删除结点操作:时间复杂度为 O(1)

  6. 求结点长度:时间复杂度为 O(n),遍历,每次增加 1

3.3 双向链表

3.3.1 定义

下面的是一份基于Java的双向链表的实现:

public class LinkedList {

transient int size = 0;

transient Node first;

transient Node last;

private static class Node {

E item;

Node next;

Node prev;

Node(Node prev, E element, Node next) {

this.item = element;

this.next = next;

this.prev = prev;

}

}

}

3.4 静态链表

借助数组类描述链表,结点有数据域 data 和指针域 next,描述(这种设计的好处是适用于不支持指针的计算机语言)

3.5 栈

3.5.1 定义

栈是一种后进先出的数据结构,下面是一种使用单向链表实现的栈:

public class Stack{

private int size;

private Node first;

private static class Node {

E element;

Node next;

Node(E element, Node next) {

this.element = element;

this.next = next;

}

}

public void push(E element) {

first = new Node(element, first);

size++;

}

public E pop() {

if (size == 0) {

throw new UnsupportedOperationException(“The stack is empty.”);

}

size --;

Node oldFirst = first;

first = oldFirst.next;

return oldFirst.element;

}

public boolean isEmpty() {

return size == 0;

}

}

3.5.2 题目:

题1:3个不同的元素依次进栈,能得到几种不同的出栈序列?

5种,abc acb bac bca cba,最后一种如果以c开头,那么ab必然已经存入了栈中,取出的顺序只能是ba,即以c开头的只有cba.

题2:a b c d e f 以所给的顺序依次进栈,若在操作时允许出栈,这得不到的序列为?

A fedbca    B bcafed    C dcefba    D cabdef

这种题应该从每个选项的第一个字母入手,以C为例,如果d处在第一个,那么说明前面的a b c肯定已经存在栈中,那么它们必然按照c b a的顺序出来;

如果题目中的c b a的出现次序不对,那么就得不到。然后再使用相同的思路判断第二个字符的情况。答案D

3.6 队列

3.6.1 普通队列

队列也是一种线性表,特性是先入先出,队列和栈的主要区别是插入、删除操作的限定不一样。下面是基于 Java 的一种使用链表来实现的队列:

public class Queue {

private Node first, last;

private int size;

private static class Node {

E element;

Node next;

Node(E element, Node next) {

this.element = element;

this.next = next;

}

}

public void enqueue(E element) {

size++;

Node node = new Node(element, null);

if (last == null) {

first = node;

last = node;

return;

}

last.next = node;

last = node;

}

public E dequeue() {

if (size == 0) {

throw new UnsupportedOperationException(“The queue is empty.”);

}

size–;

E element = first.element;

first = first.next;

return element;

}

public boolean isEmpty() {

return size == 0;

}

}

3.6.2 双端队列

队首和队尾都允许入队和出队的队列。

3.6.3 应用:
  1. 栈在括号匹配中的应用:与 [([][])] 类似的括号匹配的问题,遇到一个左括号,判断是否合法,若合法就先存在栈中,等待右括号出现,看是否匹配;

  2. 栈在表达式求值中的应用:中缀:A+B*(C-D)-E/F,后缀:ABCD-*+EF/-,然后按照计算的规则,依次进栈、出栈即可求得表达式的结果;

  3. 栈在递归中的应用:递归函数在求解的时候,要不断返回结果、传入参数等,因此效率不高,可以借助栈将递归问题转换为非递归问题;

  4. 队列在层次遍历中的应用:比如遍历二叉树等;

  5. 队列在计算机系统中的应用:用于任务分配,当任务无法立刻全部完成的时候,对无法立刻完成的任务,先将其存入到队列中,等待其他任务完成之后再去执行这些任务。

3.7 背包

背包是一种不支持从中删除元素的集合数据类型,它的目的就是帮助用例收集并迭代遍历所有收集到的元素。使用背包的很多场景可能使用栈或者队列也能实现,但是使用背包可以说明元素存储的顺序不重要。下面的是一份基于 Java 的背包的实现,在这里我们只是在之前栈的代码的基础之上做了一些修改,并让其实现 Iterable 接口以在 foreach 循环中使用背包遍历元素:

public class Bag implements Iterable{

private int size;

private Node first;

private static class Node {

E element;

Node next;

Node(E element, Node next) {

this.element = element;

this.next = next;

}

}

public void add(E element) {

first = new Node(element, first);

size++;

}

public Iterator iterator() {

return new ListIterator();

}

private class ListIterator implements Iterator {

private Node current = first;

@Override

public boolean hasNext() {

return current != null;

}

@Override

public E next() {

E element = current.element;

current = current.next;

return element;

}

@Override

public void remove() {}

}

public boolean isEmpty() {

return size == 0;

}

}

4、非线性表


4.1 树

4.1.1 概念
  1. 根:树的最上层的顶点;

  2. 父结点:某个节点上面的节点;

  3. 祖先结点:父节点的父节点等;

  4. 结点的度:树中结点的子结点个数;

  5. 树的度:树中结点的最大度数;

  6. 分支结点:度大于 0 的结点;

  7. 叶子结点:度等于 0 的结点;

  8. 树的高度:树中结点的最大层数

  9. 路径:树中两个结点之间所经过的结点序列

  10. 路径长度:路径上经过的边的个数

  11. 树的路径长度:从树根到每一结点的路径长度之和

  12. 森林:多个树就组成了森林,只要把树个根结点删去就成了森林,只要给n课树加上结点,就成了树。

4.1.2 题目

题:一棵有n个结点的树,所有结点的度数之和为_______.

问题转换成:一棵有3个结点的树,所有结点的度数之和为____. 因为题目是选择,所以应该尽量简化题目。答案n-1

4.2 二叉树

  1. 二叉树:每个结点的度不大于2的树;

  2. 满二叉树:除了叶子结点,其他结点的度都为2,也就是不存在只有1个结点的分支;

  3. 完全二叉树:相对于满二叉树,它有的结点度不为2,但是存在的分支的编号与满二叉树相同

image

在上图中左侧的是完全二叉树,右侧的是满二叉树。

说明:所谓的编号就是指每层从左到右,按照满二叉树的形式编号,上面的满二叉树每个结点的值就是它们的编号。这个编号也是我们在使用顺序存储的时候对应数组的下标。

4.2.1 二叉树的存储结构

1.顺序存储

这种存储方式,可以理解为使用数组存储,注意开始存储的下标是1,这是为了与二叉树的性质对应,另外有时候我们也可以将数组的第一个元素作为哨兵。顺序存储的基本思想是,按照满二叉树的编号顺序,如果指定编号(其实就是数组的下标)处有结点的话,数组指定位置的值即为结点的值,否则为0(表示空结点)。当然,也可以在各个元素中存放一些具有具体含义的值。

如图所示的树在数组中的实际存储为:- 1 2 3 0 4 0 5 0 0 6 0(第0位不使用)。

2.链式存储

下面是使用Java代码实现的一个二叉树,这里每个结点要包含左右两个子结点以及相应的数据实体。显然,

public class Tree {

private Node root;

private static class Node {

E element;

Node leftChild;

Node rightChild;

Node(Node leftChild, E element, Node rightChild) {

this.leftChild = leftChild;

this.element = element;

this.rightChild = rightChild;

}

}

}

4.2.2 遍历
  1. 先序遍历:a.访问根结点  b.按照先序遍历左子树  c.按照先序遍历右子树

  2. 中序遍历:a.按照中序遍历左子树  b.访问根结点  c.按照中序遍历右子树

  3. 后序遍历:a.按照后序遍历右子树  b.按照后序遍历左子树  c.访问根结点

  4. 层次遍历:借助队列,先将根节点入队,然后出队,访问该结点,将其子结点入队,访问其根结点…直到队列为空。

说明:上述三幅图从左到右的遍历方式依次是先序遍历、中序遍历和后序遍历。

作为练习,这里给出遍历二叉树的方法,可以观察一下二叉树的实现,以及中序遍历的时候输出的二叉树的值,其中 outNode() 方法用来输出结点的值:

/* 先序遍历 */

public void former() {

former(root);

}

private void former(Node<Key, Value> node) {

if (node == null) return;

outNode(node); // 先序

former(node.leftChild);

former(node.rightChild);

}

/* 中序遍历,注意中序输出的结果和排序的结果的关系 */

public void center() {

center(root);

}

private void center(Node<Key, Value> node) {

if (node == null) return;

center(node.leftChild);

outNode(node); // 中序

center(node.rightChild);

}

/* 后序遍历 */

public void latter() {

latter(root);

}

private void latter(Node<Key, Value> node) {

if (node == null) return;

latter(node.leftChild);

latter(node.rightChild);

outNode(node); // 后序

}

结论:

  1. 可以看出所谓的中序、先序和后序的主要区别就在于输出遍历结果时候的位置;

  2. 中序遍历的时候输出结果就是二叉堆的元素的从小到大的排序结果。

  3. 那么从上面的操作中可以看出,所谓的中序就是将输出操作夹在了两个递归之间。因此,如果指定的树不是二叉树,而是多叉树,也就是我们使用一个列表来保存各个子结点,那么是没有中序输出的。

4.2.3 构造二叉树

注意如果只知道二叉树的先序序列和后序序列是无法唯一地确定一棵二叉树的。

image

如图所示的二叉树,它的三种遍历方式:

  1. 先序遍历结果是:-  +  a  *  b  -  c  d  /  e  f

  2. 中序遍历结果是:a  +  b  *  c  -  d  -  e  /  f

  3. 后序遍历结果是:a  b  c  d  -  *  +  e  f  /  -

说明:先序遍历的时候,根结点处在第1的位置;中序遍历的时候根节点前面是左子树,后面是右子树;后序遍历的时候,根结点处在最后的位置。可以根据上面的思路,依次进行判断,从而可以写出完整的树。

4.2.4 二叉树的性质
  1. 二叉树的第i层上至多有 2i-1 个结点(i>=1)

  2. 深度为k的二叉树至多有 2k-1 个结点(k>=1)

  3. 对任何一棵二叉树T,如果其终端结点数为 n0,度为 2 的结点树为 n2,则 n0=n2+1.

  4. 具有 n 个结点的完全二叉树的深度为 (log2n + 1) 向下取整的结果

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司19年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司19年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

[外链图片转存中…(img-mUMVtvWz-1711991657559)]

【算法合集】

[外链图片转存中…(img-tRQq6XjD-1711991657559)]

【延伸Android必备知识点】

[外链图片转存中…(img-OKWoNqXW-1711991657559)]

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值