算法是什么(二)手写个链表(java)
算法是什么(二)手写个链表(java)
liuyuhang原创,未经允许禁止转载
目录
很多语言的API中都提供了链表实现,或者扩展库中实现了链表。
但是更多的情况下,Map(或hash)和List(非定容数组)的使用率更高。
这并非意味着链表不应该掌握或不使用了。
链表本质上是一种及其高等的数据结构展现,扩展性极强。
链表可轻松扩展成树结构,二叉树,环,栈,队列,双向队列等。
很多种数据结构都是依据链表的形式扩展出来的,虽然我知道的并不多,但是我知道链表的重要性。
所以,手写一个链表试试。
1、本质
链表的本质是Node(节点),其中保存着信息(info),前一个节点(prevNode),后一个节点(nextNode)。
和基础操作API构成
2、特性
链表为了操作的方便性,多数会将链表做成双向链表,即既包含next,又包含prev
3、基础API
链表的操作,至少需要增删改查,不然还算啥容器了:
增:默认从末尾添加,添加指定index,在首添加三种方式添加单一元素。
删:删除头,删除尾,删除指定index的元素,删除当前指针元素。
改:设置头,设置尾,设置指定index的元素,设置当前指针元素。
查:获取当前指针元素,获取首元素,获取尾元素,获取下一个元素,获取上一个元素,获取指定index的元素
有些API还提供了更多的操作:
获取当前容器的size
获取当前指针的index
迭代器
排序工具
判空
克隆
转数组
逆转
去重复
序列化
等等。。。
链表可做的操作会比想象的多的多。
4、Java中的链表
Java中常用的链表是LinkedList,实现了List接口,继承AbstractLinkedList。同时还有其他接口
同时,还有Queue大类,并非在Collection接口下,但是底层有些是使用链表实现的,功能有些是重复的。
对于需要作为原子操作的各种功能的队列来说,可以考虑。
在扩展Java中的链表的时候,有几种方式供选择:
①继承LinkedList,添加扩展算法;
②实现List,继承AbstractLinkedList,同时扩展算法;
③使用装饰模式,在构造器中调用链表的构造器,同时扩展算法;
④不受约束自己写一个吧。。。
5、写一个简单的链表
我尝试写了一个简单的链表,以前也大概看过C的链表和Java的链表,写的过程中全凭记忆,
大约花了十个小时才写完,哩哩啦啦好多天。
代码拙劣,为了以后尝试链表的其他算法(排序,转换,反转,环链表,扩展二叉树)做准备。
代码如下:
package com.FM.ArrayStudy; public class SimpleLinkedList<T> { private Node<T> pointer;// 当前指针节点
private Node<T> firstNode;// 首个节点
private Node<T> lastNode;// 末尾节点
private Integer index = 0;// 当前指针index
private Integer size = 0;// 当前容量 /**
* 获取当前pointer的info
* @return
*/
public T getThis() {
if (null == pointer) {
return firstNode.info;
} else {
return pointer.info;
}
} /**
* 获取下一个元素的内容,若没有下一个元素,则返回null
*
* @return
*/
public T getNext() {
if (index.equals(size - 1)) {
return null;
} else {
if (null == pointer) {
pointer = firstNode;
pointer = pointer.next;
T info = pointer.info;
index++;
return info;
} else {
pointer = pointer.next;
T info = pointer.info;
index++;
return info;
}
}
} /**
* 修改指定index的元素的方法
*
* @param index
* @param t
* @throws Exception
*/
public void set(Integer index, T t) throws Exception {
if (index > -1 && index < size - 1) {
Node<T> node = getNodeByIndex(index);
node.info = t;
} else {
throw new Exception("get ele " + index + " out of index");
}
} /**
* 修改首元素
*
* @param t
*/
public void setFirst(T t) {
firstNode.info = t;
} /**
* 修改尾元素
*
* @param t
*/
public void setLast(T t) {
lastNode.info = t;
} /**
* 从指定index移除node的方法
*
* @param index
* @throws Exception
*/
public void remove(Integer index) throws Exception {
if (index > -1 && index < size) {
if (index.equals(0)) {
Node<T> node = getNodeByIndex(1);
firstNode = node;
firstNode.prve = null;
} else if (index.equals(size - 1)) {
Node<T> node = getNodeByIndex(size - 2);
lastNode = node;
lastNode.next = null;
} else {
Node<T> node = getNodeByIndex(index);
Node<T> nextNode = node.next;
Node<T> prveNode = node.prve;
prveNode.next = nextNode;
nextNode.prve = prveNode;
node = null;
}
size--;
} else {
throw new Exception("get ele " + index + " out of index");
} } /**
* 获取当前元素在链表中的位置
*
* @return
*/
public int getIndex() {
return index;
} /**
* 获取当前链表size的方法
*
* @return
*/
public Integer size() {
return size;
} /**
* 判断容器是否为空的方法,为空返回true
*
* @return
*/
public boolean isEmpty() {
if (size.equals(0)) {
return true;
} else {
return false;
} } /**
* 根据index查询链表中元素的方法
*
* @param index
* @return
* @throws Exception
*/
public T getByIndex(Integer index) throws Exception {
if (index > -1 && index < size) {
Node<T> nodeByIndex = getNodeByIndex(index);
return nodeByIndex.info;
} else {
throw new Exception("get ele " + index + " out of index");
}
} /**
* 根据index获取node的方法
*
* @param index
* @return
*/
private Node<T> getNodeByIndex(Integer index) {
Node<T> temp = firstNode;// 取firstnode
if (index != 0) {// 查看当前index,若index!=0,则递归直到index
for (int i = 0; i < index; i++) {
temp = temp.next;
}
}
this.index = index;// 调整当前index
return temp;// 返回节点
} /**
* 向链表末尾默认添加一个元素的方法
*
* @param t
*/
public void add(T t) {
if (size == 0) {// 首次创建
Node<T> node = new Node<T>();
firstNode = node;
lastNode = node;
node.info = t;
size++;
} else {
lastNode.next = new Node<T>();
lastNode.next.info = t;
lastNode.next.prve = lastNode;
lastNode = lastNode.next;
size++;
}
} /**
* 在首添加元素
*
* @param t
*/
public void addFirst(T t) {
if (size == 0) {
add(t);
} else {
Node<T> node = new Node<T>();
node.info = t;
node.next = firstNode;
node.prve = null;
firstNode.next = node;
size++;
}
} /**
* 在尾部添加元素
*
* @param t
*/
public void addLast(T t) {
add(t);
} /**
* Node节点 链表内部数据结构和指针
*
* @author Liuyuhang
* @param <T>
*/
private class Node<T> {
T info;// 储存info
Node<T> next;// 下一个节点指针
Node<T> prve;// 上一个节点指针 @Override
public String toString() {// 同时打印next和prev会导致无限引用,堆栈溢出
return "Node [info=" + info + ", next=" + next + "]";
} } @Override
public String toString() {// 打印first节点会因为next引出整个链表的所有内容
return "SimpleLinkedList [node=" + firstNode + "]";
} }
测试可用,自己拿去玩吧。
以上!
算法是什么(二)手写个链表(java)的更多相关文章
- 利用神经网络算法的C#手写数字识别(二)
利用神经网络算法的C#手写数字识别(二) 本篇主要内容: 让项目编译通过,并能打开图片进行识别. 1. 从上一篇<利用神经网络算法的C#手写数字识别>中的源码地址下载源码与资源, ...
- 利用神经网络算法的C#手写数字识别(一)
利用神经网络算法的C#手写数字识别 转发来自云加社区,用于学习机器学习与神经网络 欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 下载Demo - 2.77 MB (原始地址):handwri ...
- 利用神经网络算法的C#手写数字识别
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 下载Demo - 2.77 MB (原始地址):handwritten_character_recognition.zip 下载源码 - 70. ...
- k最邻近算法——使用kNN进行手写识别
上篇文章中提到了使用pillow对手写文字进行预处理,本文介绍如何使用kNN算法对文字进行识别. 基本概念 k最邻近算法(k-Nearest Neighbor, KNN),是机器学习分类算法中最简单的 ...
- 在opencv3中实现机器学习算法之:利用最近邻算法(knn)实现手写数字分类
手写数字digits分类,这可是深度学习算法的入门练习.而且还有专门的手写数字MINIST库.opencv提供了一张手写数字图片给我们,先来看看 这是一张密密麻麻的手写数字图:图片大小为1000*20 ...
- 二. 手写SpringMVC框架
1.1 新建DispatcherServlet 1.2 在src目录下,新建applicationContext.xml <?xml version="1.0" encodi ...
- 手写数字识别的k-近邻算法实现
(本文为原创,请勿在未经允许的情况下转载) 前言 手写字符识别是机器学习的入门问题,k-近邻算法(kNN算法)是机器学习的入门算法.本文将介绍k-近邻算法的原理.手写字符识别问题分析.手写字符识别的k ...
- 机器学习框架ML.NET学习笔记【5】多元分类之手写数字识别(续)
一.概述 上一篇文章我们利用ML.NET的多元分类算法实现了一个手写数字识别的例子,这个例子存在一个问题,就是输入的数据是预处理过的,很不直观,这次我们要直接通过图片来进行学习和判断.思路很简单,就是 ...
- java - day015 - 手写双向链表, 异常(续), IO(输入输出)
类的内存分配 加载到方法区 对象在堆内存 局部变量在栈内存 判断真实类型,在方法区加载的类 对象.getClass(); 类名.class; 手写双向链表 package day1501_手写双向链表 ...
随机推荐
- java设计模式之抽象工厂模式学习
工厂模式有个问题就是,类的创建依赖工厂.要想增加一个工厂类,就要修改原来的代码,这违背了闭包原则.所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的 ...
- css3之背景定位
属性: background-position: left top || left bottom || right top || right bottom || center center || 像素 ...
- JavaEE中表现层、持久层、业务层的职责分析(转载)
表现层.持久层.业务层 注:本文转载于:http://www.blogjava.net/jiabao/archive/2007/04/08/109189.html 为了实现web层(struts)和持 ...
- ASICS各跑鞋分类及选购方法
从跑吧转来的,老帖子后面的鞋子可能不能与时俱进 不过前面的方法不错. 1简介: ASICS鞋子鞋底如果有AHAR或AHAR+的为超耐磨标志,而且超耐度一般都是黑色,用指甲刮鞋底时如刮车轮底胶.ASIC ...
- 01_Zookeeper简述
[Zookeeper应用场景] zookeeper作为一个开源的分布式应用协调系统,已经用到了许多分布式项目中,用来完成统一命名服务.状态同步服务.集群管理.分布式应用配置项的管理等工作. [Zook ...
- Android 集成百度统计
在这里简单的介绍下怎么统计自己研发的APP 的用户活跃度,和使用量,以此来展示自己APP的用户使用量! 我们的APP都需要注入数据分析,以供我们实时的了解APP的下载和使用量提供了依据! 不过我还是更 ...
- ES6入门——let和const命令
let和const命令 1.let命令 用法:类似于var,用来声明一个变量,区别是所声明的变量只在let命令所在的代码块内有效. let命令很适合用在for循环的计数器中,因为let声明的变量仅在作 ...
- “云中论道”之——使用开源技术和Azure公有云服务快速搭建云端IoT解决方案(上)
“云中论道”技术课堂第一课开讲啦!微软各路技术咖们齐聚一堂,为大家带来干货不断!作为“云中论道“课堂的开课之作,我们首先邀请到了微软Azure专家级的架构师:槐长清,他为我们带来了关于“使用开源技术和 ...
- SQL Server ->> SQL Server 2016新特性之 --- Query Store
前言 SQL Server 2016引入新的查询语句性能监控.调试和优化工具/功能 -- Query Store.以前我们发现一条查询语句性能突然下降,我们要去找出问题的所在往往需要通过调用一些DMV ...
- SQL点点滴滴_UPDATE小计
1.更新tb_card中c_customer字段的值等于tb_customer表中c_no的值 update tb_card set c_customer=ct.c_no from tb_custom ...