数据结构与算法(LeetCode) 第二节 链表结构、栈、队列、递归行为、哈希表和有序表
一、链表结构
1.单向链表节点结构
public class Node{
public int value;
public Node next;
public Node(int data){
value=data;
}
}
2.双向链表节点结构
public class DoubleNode{
public int value;
public DoubleNode last;
public DoubleNode next;
public DoubleNode(int data){
value=data;
}
}
3.单向链表与双向链表最简单的练习
3.1单向链表与双链表如何反转
//单向链表反转
public static Node reverseLinkedList(Node head){
Node pre =null;
Node next = null;
while(head !=null){
next=head.next;
head.next=pre;
pre=head;
head=next;
}
//返回新的头结点
return pre;
}
//双向链表反转
public static DoubleNode reverseDoubleList(DoubleNode head){
DoubleNode pre=null;
DoubleNode next=null;
while(head!=null){
next=head.next;
head.next=pre;
head.last=next;
pre=head;
head=next;
}
//返回头结点
return pre;
}
3.2把给定值删除
//删除一个单链表中值为num的节点
public static Node removeValue(Node head,int num){
//判断头部节点需要删多少个
//如在3-3-3-3-2-2-1链表中,删掉值为3的节点,则需要删掉4个头部节点
while(head !=null){
if(head.value !=num){
break;
}
head=head.next;
}
//head来到第一个不需要删除的位置
Node pre=head;
Node cur=head;
while(cur != null){
//注意:java中会自动释放无法找到的节点,不需要手动释放
if(cur.value == num){
pre.next =cur.next;
}else{
pre=cur;
}
cur= cur.next;
}
retuen pre;
}
二、栈和队列
1.逻辑概念
栈:数据先进后出
队列:数据先进先出
2.栈和队列的实际实现
双向链表实现
数组实现
1.使用双向链表实现栈和队列
(1)使用双向链表模拟栈与队列的进出操作
public static class DoubleEndsQueue<T>{
public Node<T> head;//头指针
public Node<T> tail;//尾指针
//如果从头部开始加节点采用以下方法
public void addFormHead(T value){
Node<T> cur=new Node<T>(value);
if(head==null){
head=cur;
tail=cur;
}else{
cur.next=head;
head.last=cur;
head=cur;
}
}
//如果从尾部开始加节点采用以下方式
public void addFromBottom(T value){
Node<T> cur =new Node<T>(value);
if(head ==null){
head=cur;
tail=cur;
}else{
cur.last=tail;
tail.next=cur;
tail=cur;
}
}
//从头部弹出节点
public T popFromHead(){
if(head==null){
return null;
}
Node<T> cur=head;
if(head==tail){//如果链表中只有一个节点
head=null;
tail=null;
}else{
head=head.next;
cur.next=null;
head.last=null;
}
return cur.value;
}
//从尾部弹出节点
public T popFromBottom(){
if(head==null){
return null;
}
Node<T> cur=tail;
if(head==tail){//如果链表中只有一个节点
head=null;
tail=null;
}else{
tail=tail.last;
tail.next=null;
cur.last=null;
}
return cur.value;
}
}
(2)双向链表创建栈
public static class MyStack<T{
private DoubleEndsQueue<T> queue;
public MyStack(){
queue=new DoubleEndsQueue<T>();
}
//从头部插入从头部弹出,实现先进后出
//往栈中插入数据
public void push(T value){
queue.addFromHead(value);
}
//将数据弹出栈
public T pop(){
return queue.popFromHead();
}
//判断是否为空
public boolean isEmpty(){
return queue.isEmpty();
}
}
(3)双向链表创建队列
public static class MyQueue<T{
private DoubleEndsQueue<T> queue;
public MyStack(){
queue=new DoubleEndsQueue<T>();
}
//从头部插入从尾部弹出,实现先进先出
//往栈中插入数据
public void push(T value){
queue.addFromHead(value);
}
//将数据弹出栈
public T pop(){
return queue.popFromBottom();
}
//判断是否为空
public boolean isEmpty(){
return queue.isEmpty();
}
}
2.使用数组实现栈和队列
提示:只考虑固定大小数组
(1)数组实现队列:实现环形数组
public static class MyQueue{
private int[] arr;
private int pushi;//记录插入数据的位置
private int polli;//记录弹出数据的位置
private int size;//记录队列中的数据个数
private final int limit;//数组大小
//初始化数组
publish MyQueue(int limit){
arr=new int[limit];
pushi = 0;
polli=0;
size=0;
this.limit=limit;
}
//进队列
public void push(int value){
if(size==limit){
throw new RuntimeException("队列已满,不可再入队")
}
size++;
arr[pushi]=value;
pushi=nextIndex(pushi);
}
//出队列
public int pop(){
if(size==0){
throw new RuntimeException("栈为空");
}
size--;
int ans=arr[polli];
polli=nextIndex(polli);
return ans;
}
//判断是否为空
public boolean isEmpty(){
return size==0;
}
//如果现在的下标是i,返回下一个位置,
private int nextIndex(int i){
//判断i是否到了数组的最后一个位置,如果是,从0开始
return i<limit-1 ? i+1:0;
}
}
(2)数组实现栈
public static class MyStack{
private int[] arr;
private int size;//记录栈的数据大小
private final int limit;//数组大小
//初始化数组
publish MyQueue(int limit){
arr=new int[limit];
size=0;
this.limit=limit;
}
//进栈
public void push(int value){
if(size==limit){
throw new RuntimeException("队列已满,不可再入队")
}else{
size++;
arr[size]=value;
}
}
//出栈
public int pop(){
if(size==0){
throw new RuntimeException("栈为空");
}
size--;
int ans=arr[size];
return ans;
}
//判断是否为空
public boolean isEmpty(){
return size==0;
}
}
3.栈和队列的常见面试题
(1)实现一个特殊的栈,在基本功能的基础上,再实现返回栈中最小元素的功能
1) pop、push、getMin操作的时间复杂度都是O(1)。
2)设计的栈类型可以使用现成的栈结构。实现思路:准备两个栈,一个栈为正常的数据栈Data,一个栈Min来存放最小值,每次插入一个新数据newNum,Data正常插入,插入Min中是每次要与栈顶比较大小
public static class MyStack2{
//创建两个栈
private Stack<Integer> stackData;
private Stack<Integer> stackMin;
public MyStack2(){
this.stackData=new Stack<Integer>();
this.stackMin=new Stack<Integer>();
}
public void push(int newNum){
//往stackMin中放数据时,需要将数据与Min栈顶的数据进行比较,
// 以确保Min插入的每一个数据都是最新的最小值
if(this.stackMin,isEnpty()){
this.stackMin.push(newNum);
}else if(newNum<this.getmin()){
this.stackMin.push(newNum);
}else{
int newMin =this.stackMin.peek();
this.stackMin.push(newMin);
}
this.stackData.push(newNum);
}
public int pop(){
if(this.stackData.isEmpty()){
throw new RuntimeException("栈为空");
}
this.stackMin.pop();
return this.stackData.pop();
}
public int getmin(){
if (this.stackMin.isEmpty()){
throw new RuntimeException("栈为空");
}
//返回栈栈顶数据
return this.stackMin.peek();
}
}
三、递归
判断递归的复杂度
Master公式
形如 T(N)= a * T(N/b)+O(N^d)(其中的a、b、d都是常数)的递归函数,可以直接通过Master公式来确定时间复杂度如果log(b,a)< d,复杂度为O(N^d)
如果log(b,a) > d,复杂度为O(N^log(b,a))
如果log(b,a) == d,复杂度为O(N^d * logN)
四、哈希表与有序表
1.哈希表(HashMap)
1)哈希表在使用层面上可以理解为一种集合结构
2)如果只有key,没有伴随数据value,可以使用HashSet结构
3)如果既有key,又有伴随数据value,可以使用HashMap结构
4)有无伴随数据,是HashMap和HashSet唯一的区别,实际结构是一回事
5)使用哈希表增(put)、删(remove)、改(put)和查(get)的操作,可以认为时间复杂度为o(1),但是常数时间比较大
6)放入哈希表的东西,如果是基础类型,内部按值传递,内存占用是这个东西的大小
7)放入哈希表的东西,如果不是基础类型,内部按引用传递,内存占用是8字节
2.有序表(TreeMap)
1)有序表在使用层面上可以理解为一种集合结构。
2)如果只有key,没有伴随数据value,可以使用set结构
3)如果既有key,又有伴随数据value,可以使用map结构
4)有无伴随数据是set与map的唯一区别,底层的实际结构是一回事。
5)有序表和哈希表的区别是,有序表把key按顺序组织起来,而哈希表完全不组织。
6)只要是有序表,他的常见操作的时间复杂度都是O(logN)
数据结构与算法(LeetCode) 第二节 链表结构、栈、队列、递归行为、哈希表和有序表的更多相关文章
- Java数据结构和算法(一)线性结构之单链表
Java数据结构和算法(一)线性结构之单链表 prev current next -------------- -------------- -------------- | value | next ...
- 数据结构与算法【Java】08---树结构的实际应用
前言 数据 data 结构(structure)是一门 研究组织数据方式的学科,有了编程语言也就有了数据结构.学好数据结构才可以编写出更加漂亮,更加有效率的代码. 要学习好数据结构就要多多考虑如何将生 ...
- Java数据结构和算法(一)线性结构
Java数据结构和算法(一)线性结构 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 线性表 是一种逻辑结构,相同数据类型的 ...
- 【学习总结】java数据结构和算法-第三章-稀疏数组和队列
相关链接 [学习总结]尚硅谷2019java数据结构和算法 github:javaDSA 目录 稀疏数组 队列 稀疏数组 稀疏数组介绍 图示 应用实例 代码实现 SparseArray.java:与二 ...
- JavaScript 版数据结构与算法(三)链表
今天,我们要讲的是数据结构与算法中的链表. 链表简介 链表是什么?链表是一种动态的数据结构,这意味着我们可以任意增删元素,它会按需扩容.为何要使用链表?下面列举一些链表的用途: 因为数组的存储有缺陷: ...
- Java数据结构和算法(七)——链表
前面博客我们在讲解数组中,知道数组作为数据存储结构有一定的缺陷.在无序数组中,搜索性能差,在有序数组中,插入效率又很低,而且这两种数组的删除效率都很低,并且数组在创建后,其大小是固定了,设置的过大会造 ...
- 为什么我要放弃javaScript数据结构与算法(第二章)—— 数组
第二章 数组 几乎所有的编程语言都原生支持数组类型,因为数组是最简单的内存数据结构.JavaScript里也有数组类型,虽然它的第一个版本并没有支持数组.本章将深入学习数组数据结构和它的能力. 为什么 ...
- 数据结构与算法之美 06 | 链表(上)-如何实现LRU缓存淘汰算法
常见的缓存淘汰策略: 先进先出 FIFO 最少使用LFU(Least Frequently Used) 最近最少使用 LRU(Least Recently Used) 链表定义: 链表也是线性表的一种 ...
- 为什么我要放弃javaScript数据结构与算法(第三章)—— 栈
有两种结构类似于数组,但在添加和删除元素时更加可控,它们就是栈和队列. 第三章 栈 栈数据结构 栈是一种遵循后进先出(LIFO)原则的有序集合.新添加的或待删除的元素都保存在栈的同一端,称为栈顶,另一 ...
- 剑指offer_面试题5_从尾到头打印链表(栈和递归实现)
题目:输入一个链表的头结点,从尾到头反过来打印出每一个节点的值 考察 单链表操作.栈.递归等概念. 理解:要实现单链表的输出,那么就须要遍历.遍历的顺序是从头到尾.而节点输出的顺序是从尾到头.因此,先 ...
随机推荐
- Rust 学习笔记:快速上手篇
Rust 学习笔记:快速上手篇 这篇学习笔记将用于记录本人在快速上手 Rust 编程语言时所记录的学习心得与代码实例.为此,我会在本笔记库项目的Programming/LanguageStudy/目录 ...
- 如何在Avalonia11中设置自定义字体
如何在Avalonia11中设置自定义字体 由于avalonia默认的中文字体显示的效果不太理想,我们需要下载一些自定义的字体,来优化UI的显示效果.avalonia的官方文档地址. 对我在项目中运用 ...
- RAT蓝队自动化测试框架
RAT蓝队自动化测试框架 介绍 RAT 是根据 MITRE ATT&CK 战术矩阵测试蓝队检测能力的脚本框架,由 python2.7 编写,共有 50 多种不同 ATT&CK 技术点和 ...
- Flutter状态管理-FlyingRedux
简介 Flying Redux 是一个基于Redux状态管理的组装式flutter应用框架. 它有四个特性: 函数式编程 可预测的状态 插拔式的组件化 支持null safety 和 flutter ...
- WebSSH之录屏安全审计(三)
第一篇:Gin+Xterm.js实现WebSSH远程Kubernetes Pod(一) 第二篇:WebSSH远程管理Linux服务器.Web终端窗口自适应(二) 支持用户名密码认证 支持SSH密钥认证 ...
- Angular:error TS2717: Subsequent property declarations must have the same type. Property 'contentRect' mu st be of type 'DOMRectReadOnly', but here has type 'DOMRectReadOnly'.
解决方案 在tsconfig.json的compilerOptions选项中添加如下内容"skipLibCheck": true. 如下图所示 之后重新启动项目. 如下图启动成功
- html中的一些常用标签与标签属性
label for属性 定义和用法 for 属性规定 label 与哪个表单元素绑定. <span> <label for="username">用户账号& ...
- Django创建超级管理员用户
python manage.py createsuperuser 后面就会提示你输入用户名.邮箱以及密码.
- [oracle]用户与权限管理
创建用户 CREATE USER 用户名 IDENTIFIED BY 密码 DEFAULT TABLESPACE 表空间 TEMPORARY TABLESPACE 临时表空间 QUOTA 空间配额大小 ...
- ESP32C3 LEDC_PWM
LEDC_PWM LED 控制器 (LEDC) 主要用于控制 LED,也可产生 PWM 信号用于其他设备的控制,ESP32C3有 6 路通道.设置 LEDC 通道分三步完成.与 ESP32 不同 ...