算法是什么(二)手写个链表(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_手写双向链表 ...
随机推荐
- mybatis整合spring的时候配置数据库信息文件properties注意事项
信息后面不能有空格 ,格式要xxx.driver xxx.url 这样
- DUANG~ 万网轻云服务器,大促狂欢,不仅仅免单!
DUANG~ 万网轻云服务器,大促狂欢,不仅仅免单! 当老板第一次知道我们要做活动的时候,其实是拒绝的.DUANG~ 打折.降价.挥泪甩卖…太俗套.客户看到一定骂我们,根本没有诚意. 所以轻云大促 ...
- 【Machine Learning】训练集 验证集 测试集区别
最近在Udacity上学习Machine learning课程,对于验证集.测试集和训练集的相关概念有些模糊.故整理相关资料如下. 交叉检验(Cross Validation) 在数据分析中,有些算法 ...
- Qt 资料大全
https://blog.csdn.net/liang19890820/article/details/51752029 简述 发福利了.发福利了.发福利了,重要的事情说三遍... 为了方便更多Qte ...
- 如何解决 Linux 虚拟机磁盘设备名不一致的问题
问题描述 在 Linux 虚拟机内,将附加的多块数据磁盘以设备名(/dev/sdxx)的方式创建文件系统,并将之写入 /etc/fstab 文件中实现启动自动挂载功能.但是在虚拟机重启之后,会随机出现 ...
- Hadoop HA集群的搭建
HA 集群搭建的难度主要在于配置文件的编写, 心细,心细,心细! ha模式下,secondary namenode节点不存在... 集群部署节点角色的规划(7节点)------------------ ...
- SQL Server 2016 ->> T-SQL新特性
1) TRUNCATE表分区而不是整表 CREATE TABLE dbo.TruncatePartitionTest ( PrtCol INT, Col2 ) ) ON [myPS1](PrtCol) ...
- 【Leetcode】【Medium】Rotate List
Given a list, rotate the list to the right by k places, where k is non-negative. For example:Given 1 ...
- windows系统的错误码
https://blog.csdn.net/u011785544/article/details/51682290
- Realtek无线网卡对于Ubuntu的WiFi不支持的处理办法
1.应急办法:查询rfkill list all,可以看到ideapad_laptop的无线被物理关闭,可是博主的笔记本根本没这个键位,所以执行sudo modprobe -r ideapad_lap ...