数据结构-自定义栈、队列、二分查找树、双向链表

/**
 * 底层是数组
 */
public class MyStack {
	private long [] arr; // 底层是数组
	private int top = -1; // 核心【栈顶的索引(指针)】
	
	public MyStack() {
		super();
		arr = new long[10];
	}
	
	public MyStack(int capacity) {
		super();
		arr = new long[capacity]; // 自定义长度
	}
	
	/**
	 * 压栈
	 * @param value
	 */
	public void push(long value) {
		if(isFull())
			throw new IllegalArgumentException("Stack is full");
		arr[++top] = value;
	}
	
	/**
	 * 弹栈【每次都是从栈顶取出元素】
	 * @return
	 */
	public long pop() {
		if(isEmpty())  // 当栈空的时候,就不能弹栈了
			throw new IllegalArgumentException("Stack is empty");
		return arr[top--];
	}
	
	/**
	 * 查看栈顶的元素
	 * @return
	 */
	public long peek() {
		if(isEmpty())  // 当栈空的时候,就不能弹栈了
			throw new IllegalArgumentException("Stack is empty");
		return arr[top];
	}
	
	/**
	 * 判断栈是否是空的
	 * @return
	 */
	public boolean isEmpty() {
		return top == -1;
	}
	
	/**
	 * 判断是否满栈了
	 * @return
	 */
	public boolean isFull() {
		return top == arr.length-1;
	}
}




队列

/**
 * 自定义队列  FIFO : 先进先出  【底层是数组】
 */
public class MyQueue {
	private long [] arr; // 底层是数组
	private int front = 0; // 队头索引
	private int rear = 0;  // 队尾索引
	private int elements = 0; // 队列中实际的元素个数
	
	public MyQueue() {
		super();
		arr = new long[10];
	}
	
	public MyQueue(int capacity) {
		super();
		arr = new long[capacity]; // 自定义长度
	}
	
	/**
	 * 入队列【从队尾添加元素】
	 * @param value
	 */
	public void enqueue(long value) {
		if(isFull())
			throw new QueueException("Queue is full");
		arr[rear++] = value;
		elements++;
	}
	
	/**
	 * 出队列 【从队头取出元素】
	 * @return
	 */
	public long dequeue() {
		if(isEmpty())
			throw new QueueException("Queue is empty");
		elements--;
		return arr[front++];
	}
	
	/**
	 * 查看队头的元素
	 * @return
	 */
	public long top() {
		if(isEmpty())
			throw new QueueException("Queue is empty");
		return arr[front];
	}
	
	/**
	 * 判断队列是否是空的
	 * @return
	 */
	public boolean isEmpty() {
		return elements == 0;
	}
	
	/**
	 * 队列满了
	 * @return
	 */
	public boolean isFull() {
		return elements == arr.length;
	}
	
	/**
	 * 队列中的元素个数
	 * @return
	 */
	public int size() {
		return elements;
	}
}

二分查找树

/**
 * 	二叉查找树【二叉搜索树】
 * 		1. 底层 Node
 * 		2. 树根root
 */
public class BinarySearchTree {
	
	private Node root; // 树根
	
	public BinarySearchTree() {
		super();
	}
	
	/**
	 * 	二叉树的添加【口诀 : 左小右大】
	 * @param value
	 * @return true 添加成功  false 添加失败了
	 */
	public boolean add(long value) {
		Node node = new Node(value); // 添加的新节点
		if(root == null) { // 空树
			root = node; // 把新添加的第一个元素作为树根
			return true;
		}
		Node parent = null; // 当前节点的父节点
		Node current = root; // 每次都要从树根去查询
		for(;;) {
			parent = current; // 确定当前节点的父节点
			if(value < current.data) { // 左小:值小的放节点的左边
				current = current.leftChild;
				if(current == null) {
					parent.leftChild = node;
					return true;
				}
			}else if(value > current.data) { // 右大:值大的放节点的右边
				current = current.rightChild;
				if(current == null) {
					parent.rightChild = node;
					return true;
				}
			}else { // 节点值相等了:去重
				return false; // TreeSet的去重原理【重复的节点不会添加】
			}
		}
	}
	
	/**
	 *      根据值来找二叉树中的节点(递归思想)
	 *              时间复杂度O(log2n)  ~ O(n) , 近似于二分查找
	 * @param value
	 * @return
	 */
	public Long find(long value) {
		if(root == null)  // 空树
			return null;
		Node current = root; // 每次查询都要从树根开始
		while(value != current.data) { // 没要找到此节点时,则继续遍历左/右子节点来查找
			if(value < current.data) { // 左小
				current = current.leftChild;
			}else { // 右大
				current = current.rightChild;
			}
			if(current == null) { // 找到树的最后一个节点都还没有找到该数值的节点
				return null;
			}
		}
		return current.data;
	}
	
	/**
	 *      获取树根  
	 * @return
	 */
	public Node getRoot() {
		return root;
	}

	/**
	 * 	递归 : 从任意节点进行前序遍历【根左右】
	 * @param localNode
	 */
	public void preOrder(Node localNode) {
		if(localNode != null) {
			//1. 前序遍历根节点
			System.out.println(localNode);
			//2. 前序遍历左子节点
			preOrder(localNode.leftChild);
			//3. 前序遍历右子节点
			preOrder(localNode.rightChild);
		}
	}
	
	/**
	 * 	递归 : 从任意节点进行中序遍历 【左根右】
	 * @param localNode
	 */
	public void inOrder(Node localNode) {
		if(localNode != null) {
			//1. 中序遍历左子节点
			inOrder(localNode.leftChild) ;
			//2. 中序遍历根节点
			System.out.println(localNode);
			//3. 中序遍历右子节点
			inOrder(localNode.rightChild) ;
		}
	}
	
	/**
	 * 	递归 : 从任意节点进行后序遍历 【左右根】
	 * @param localNode
	 */
	public void postOrder(Node localNode) {
		if(localNode != null) {
			//1. 后序遍历左子节点
			postOrder(localNode.leftChild); 
			//2. 后序遍历右子节点
			postOrder(localNode.rightChild); 
			//3. 后序遍历根节点
			System.out.println(localNode);
		}
	}
	
	/**
	 *	 树结构的底层节点类
	 */
	@SuppressWarnings("unused") 
	class Node{
		private long data; // 数据域
		private Node leftChild; // 当前节点的左子节点
		private Node rightChild; // 当前节点的右子节点
		public Node(long data) {
			super();
			this.data = data;
		}
		public Node getLeftChild() {
			return leftChild;
		}
		public Node getRightChild() {
			return rightChild;
		}
		@Override
		public String toString() {
			return String.valueOf(data);
		}
	}
}

双向链表


/**
 * 	双向链表
 *     1. 底层是Node(data, next ,previous)
 *     2. first头节点  last尾结点
 */
public class DoubleLinkedList {
	private Node first; // 头节点
	private Node last; // 尾节点
	private int elements; // 链表中真实的节点个数
	
	public DoubleLinkedList() {
		super();
	}

	/**
	 * 判断是否是空链表
	 * 
	 * @return
	 */
	public boolean isEmpty() {
		return first == null;
	}
	
	/**
	 * 从链表头部添加元素
	 * @param value
	 */
	public void addFirst(Object value) {
		Node node = new Node(value);
		if (first == null) { // 空链表
			last = node; // 指定尾节点
		}else { // 不是空链表时
			first.previous = node;
		}
		node.next = first;
		first = node;
		elements++;
	}
	
	
	/**
	 * 从链表尾部添加节点
	 * 
	 * @param value
	 */
	public void addLast(Object value) {
		Node node = new Node(value);
		if (first == null) { // 空链表
			first = node; // 指定尾节点
		} else {
			last.next = node; // 图步骤1:  向链表尾部追加节点
			node.previous = last; // 图步骤2 :把曾经的last变为倒数第二个节点
		}
		last = node; // 图步骤3 : 新添加的节点就是尾部节点
		elements++;
	}
	
	/**
	 *    从链表尾部添加节点
	 * @param value
	 */
	public void add(Object value) {
		 addLast(value);
	}
	
	/**
	 * 	删除链表的头节点
	 * @return
	 */
	public Object removeFirst() {
		if(first == null) // 空链表不用删除
			return null;
		Node removeNode = first; // 临时保存被删除的头节点
		if(removeNode.next == null) { // 删除到链表只剩余最后一个节点时
			last = null;
		}else {
			removeNode.next.previous = null; // 头节点是不会存在previous的
		}
		first= first.next;
		elements--;
		return removeNode.data;
	}
	
	/**
	 * 	删除链表的尾节点
	 * @return
	 */
	public Object removeLast() {
		if(first == null) // 空链表不用删除
			return null;
		Node removeNode = last; // 临时保存被删除的头节点
		if(removeNode.next == null) { // 链表只剩余最后一个元素了
			first = null;
		}else { // 链表中还有节点
			removeNode.previous.next = null; // 尾节点时没有下一个节点的
		}
		last = last.previous;
		elements--;
		return removeNode.data;
	}
	
	@Override
	public String toString() {
		Node current = first; // 双向链表从头节点开始一个个遍历元素
		StringBuilder builder = new StringBuilder();
		builder.append("[");
		while (current != null) {
			builder.append(current);
			current = current.next;
			if (current != null) {
				builder.append(", ");
			}
		}
		builder.append("]");
		return builder.toString();
	}
	
	/**
	 * 从链表尾部向前遍历(倒序)
	 * @return
	 */
	public String reverse() {
		Node current = last; // 双向链表从尾节点开始一个个遍历元素
		StringBuilder builder = new StringBuilder();
		builder.append("[");
		while (current != null) {
			builder.append(current);
			current = current.previous;
			if (current != null) {
				builder.append(", ");
			}
		}
		builder.append("]");
		return builder.toString();
	}
	
	/**
	 * 	查找节点 (双向链表可以从头节点也可以从尾节点查找)   1~1000
	 * @param value
	 * @return
	 */
	public Object find(Object value) {
		// 双端链表要从头节点first开始查找元素
		Node current = first;
		while (current != null) {
			if (current.data == value) {
				return current.data;
			}
			current = current.next; // 遍历
		}
		return null;
	}
	
	/**
	 * 	根据数据值来删除对应的链表节点
	 * @param obj
	 * @return
	 */
	public Object remove(Object value) {
		if(first == null) // 空链表不能删除节点
			return null;
		//1.遍历查找需要删除的节点	
		Node current = first; // 当前遍历的节点
		while(current.data !=  value) { // 判断节点的值是否是要删除的值
			if(current.next == null) // 已经找到链表的最后一个节点了
				return null;
			current = current.next; // 遍历思想
		}
		//2.删除查找到的节点
		if(current == first) { // 删除的就是头节点元素     
			if(current.next == null)// 处理 : 链表中就一个元素,且删除的就是这个元素时
				last = null;
			first = current.next;
		}else { // 删除的中间节点或尾结点
			current.previous.next = current.next; // current给删除了(current就成为垃圾,GC)
		}
		elements--;
		return current.data;
	}
	
	/**
	 * 	链表中真实的节点个数
	 * @return
	 */
	public int size() {
		return elements;
	}
	
	private class Node { // 底层Node节点类
		private Object data; // 数据域
		private Node next; // 指针域(保存的是下一个节点的引用)
		private Node previous; // 指针域(保存的是上一个节点的引用)

		public Node(Object data) {
			super();
			this.data = data;
		}

		@Override
		public String toString() {
			return String.valueOf(data);
		}
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/600786.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Fizzler库+C#:从微博抓取热点的最简单方法

概述 在这篇技术文章中&#xff0c;我们将深入研究如何利用Fizzler库结合C#语言&#xff0c;以实现从微博平台抓取热点信息的功能。微博作为中国乃至全球范围内具有重要影响力的社交媒体平台之一&#xff0c;在互联网信息传播中扮演着举足轻重的角色。通过Fizzler这一强大的.N…

【探索Java编程:从入门到入狱】Day4

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

电费自动抄表是什么?什么叫电费自动抄表?

1.电费自动抄表&#xff1a;简述 电费自动抄表是一种现代化电力工程管理方法&#xff0c;根据远程系统收集解决电度表数据&#xff0c;取代了传统的人工抄水表方法。这项技术提高了效率&#xff0c;降低了不正确&#xff0c;并且为消费者和电力公司提供了更多服务项目概率。 …

基于51单片机ESP8266wifi控制机器人—送餐、快递

基于51单片机wifi控制机器人 &#xff08;程序&#xff0b;原理图&#xff0b;PCB&#xff0b;设计报告&#xff09; ​功能介绍 具体功能&#xff1a; 1.L298N驱动电机&#xff0c;机器人行走&#xff1b; 2.装备红外线感应检测到周围环境&#xff0c;进行行程判断&#xf…

Windows环境编译 VVenC 源码生成 Visual Studio 工程

VVenC介绍 Fraunhofer通用视频编码器(VVenC)的开发是为了提供一种公开可用的、快速和有效的VVC编码器实现。VVenC软件基于VTM&#xff0c;其优化包括软件重新设计以减轻性能瓶颈、广泛的SIMD优化、改进的编码器搜索算法和基本的多线程支持以利用并行。此外&#xff0c;VVenC支…

124.反转链表(力扣)

题目描述 代码解决&#xff08;思路1&#xff1a;双指针&#xff09; class Solution { public:ListNode* reverseList(ListNode* head) {ListNode*temp;//保存cur下一个节点ListNode*curhead;ListNode*preNULL;while(cur){tempcur->next;// 保存一下 cur的下一个节点&#…

uniapp 监听APP切换前台、后台插件 Ba-Lifecycle

监听APP切换前台、后台 Ba-Lifecycle 简介&#xff08;下载地址&#xff09; Ba-Lifecycle 是一款uniapp监听APP切换前台、后台的插件&#xff0c;简单易用。 截图展示 也可关注博客&#xff0c;实时更新最新插件&#xff1a; uniapp 常用原生插件大全 使用方法 在 script…

Spring事件

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;Spring⛺️稳中求进&#xff0c;晒太阳 Spring事件 简洁 Spring Event&#xff08;Application Event&#xff09;就是一个观察者模式&#xff0c;一个bean处理完任务后希望通知其他Bean的…

数据交换和异步请求(JSONAjax))

目录 一.JSON介绍1.JSON的特点2.JSON的结构3.JSON的值JSON示例4.JSON与字符串对象转换5.注意事项 二.JSON在Java中的使用1.Javabean to json2.List to json3.Map to JSONTypeToken底层解析 三.Ajax介绍1.介绍2.Ajax经典应用场景 四.Ajax原理示意图1. 传统web应用2.Ajax方法 五.…

突然断电,瀚高数据库启动失败

服务器临时断电后&#xff0c;数据库启动不起来 ps -ef|grep postgres 进到数据库的data目录下看下ls 看下 查看临时文件&#xff1a; ls -la /tmp 把这两个5866的文件改个名字张老师 加个bak就行 改完了pg_ctl start起一下

618挑选家用洗地机,需要注意哪些事项?有哪些家用洗地机值得买?

近年来&#xff0c;智能清洁家电越来越受到消费者的欢迎&#xff0c;洗地机作为清洁家电的新宠&#xff0c;凭借其集扫地、拖地、杀菌清洗于一体的强大功能&#xff0c;成为市场上的热销产品。那么&#xff0c;这类洗地机真的好用吗&#xff1f;怎么挑选到好用的家用的洗地机呢…

风电厂数字孪生3D数据可视化交互展示构筑智慧化电厂管理体系

随着智慧电厂成为未来电力企业发展的必然趋势&#xff0c;深圳华锐视点紧跟时代步伐&#xff0c;引领技术革新&#xff0c;推出了能源3D可视化智慧管理系统。该系统以企业现有的数字化、信息化建设为基础&#xff0c;融合云平台、大数据、物联网、移动互联、机器人、VR虚拟现实…

BUUCTF [极客大挑战 2019]EasySQL 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; [极客大挑战 2019]EasySQL 1 密文&#xff1a; 解题思路&#xff1a; 1、根据题目提示&#xff0c;并且网站也存在输入框&#xff0c;尝试进行SQL注入。 首先&#xff0c;判断提交方式&#xff0c;随机输入数据…

EtherCAT开发_4_分布时钟知识点摘抄笔记1

分布时钟 (DC&#xff0c;Distributed Cl ock) 可以使所有EtherCAT设备使用相同的系统时间&#xff0c;从而控制各设备任务的同步执行。从站设备可以根据同步的系统时间产生同步信号&#xff0c;用于中断控制或触发数字量输入输出。支持分布式时钟的从站称为 DC 从站。分布时钟…

常见的容器技术有哪些

容器技术是一种轻量级的软件封装方式&#xff0c;它将软件代码及其依赖项打包在一起&#xff0c;这样应用可以在任何支持容器的系统上无缝运行。它允许应用程序及其依赖项在一个隔离的环境中运行&#xff0c;这个环境被称为容器。容器技术有助于提高应用程序的可移植性、一致性…

算法提高之能量项链

算法提高之能量项链 核心思想&#xff1a;区间dp 通过观察发现可以将n个珠子最后的n1个数看作石子 合并石子 在l~r的范围内 找k作隔断 #include <iostream>#include <cstring>#include <algorithm>using namespace std;const int N 110,M N<<…

景源畅信:个人抖音小店怎么开通?

在数字时代的浪潮中&#xff0c;个体创业已不再是遥不可及的梦想。特别是随着短视频平台的崛起&#xff0c;抖音不仅成为人们娱乐消遣的新宠&#xff0c;更是众多创业者眼中的“新大陆”。你是否也曾憧憬过在抖音上开一家属于自己的小店?那么&#xff0c;如何开通个人抖音小店…

[微信小程序] 入门笔记2-自定义一个显示组件

[微信小程序] 入门笔记2-自定义一个显示组件 0. 准备工程 新建一个工程,删除清空app的内容和其余文件夹.然后自己新建pages和components创建1个空组件和1个空页面. 设定 view 组件的默认样式,使其自动居中靠上,符合习惯.在app.wxss内定义,作用做个工程. /**app.wxss**/ /* 所…

【强训笔记】day12

NO.1 思路&#xff1a;哈希表&#xff0c;建立bool数组&#xff0c;将要删除的字符串存入哈希表&#xff0c;并标为true&#xff0c;再遍历要做处理的字符串&#xff0c;如果在哈希表中为false&#xff0c;就输出。 代码实现&#xff1a; #include <iostream> #includ…

大数据技术原理与技术简答

1、HDFS中名称节点的启动过程 名称节点在启动时&#xff0c;会将FsImage 的内容加载到内存当中&#xff0c;此时fsimage是上上次关机时的状态。然后执行 EditLog 文件中的各项操作&#xff0c;使内存中的元数据保持最新。接着创建一个新的FsImage 文件和一个空的 Editlog 文件…
最新文章