Linked List

  1. 用多少就申请多少内存。
  2. 链表是一种链式存储的线性表,所有元素的内存地址不一定连续的。

接口设计

代码实现

MyList.java(接口)

package com.cyb;

public interface MyList<E> {
/**
* 元素未找到
*/
static final int ELEMENT_NOT_FOUND = -1; /**
* 清除所有元素
*/
void clear(); /**
* 元素的数量
*
* @return
*/
int size(); /**
* 是否为空
*
* @return
*/
boolean isEmpty(); /**
* 是否包含某个元素
*
* @param element 元素
* @return
*/
boolean contains(E element); /**
* 添加元素至尾部
*
* @param element 元素
*/
void add(E element); /**
* 在指定索引下标处添加元素
*
* @param index 下标索引
* @param element 元素
*/
void add(int index, E element); /**
* 获取元素
*
* @param index 索引下标
* @return
*/
E get(int index); /**
* 设置index位置的元素
*
* @param index 索引下标
* @param element 元素
* @return 原来的元素
*/
E set(int index, E element); /**
* 移除指定索引处的元素
*
* @param index 索引下标
* @return
*/
E remove(int index); /**
* 查看元素的索引
*
* @param element 元素
* @return
*/
int indexOf(E element);
}

AbstractMyList.java(抽象类)

package com.cyb;

public abstract class AbstractMyList<E> implements MyList<E> {
/**
* 元素的数量
*/
protected int size; /**
* /** 元素的个数
*
* @return
*/
public int size() {
return size;
} /**
* 是否为空
*
* @return
*/
public boolean isEmpty() {
return size == 0;
} /**
* 是否包含某个元素
*
* @param element 元素
* @return
*/
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
} /**
* 添加元素到最后面
*
* @param element
*/
public void add(E element) {
add(size, element);
} protected void outOfBounds(int index) {
throw new IndexOutOfBoundsException("Index:" + index + ",Size:" + size);
} /**
* 范围检测
*
* @param index 索引下标
*/
protected void rangeCheck(int index) {
if (index < 0 || index >= size) {
outOfBounds(index);
}
} /**
* 范围检测
*
* @param index 索引下标
*/
protected void rangeCheckForAdd(int index) {
if (index < 0 || index > size) {
outOfBounds(index);
}
}
}

MyArrayList.java

package com.cyb;

/**
* 自定义ArrayList数组
*
* @author chenyanbin
*
*/
public class MyArrayList<E> extends AbstractMyList<E> { /**
* 所有元素
*/
private E[] elements;
private static final int DEFAULT_CAPACITY = 100; public MyArrayList() {
this(DEFAULT_CAPACITY);
} @SuppressWarnings("unchecked")
public MyArrayList(int capacity) {
capacity = (capacity < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capacity;
elements = (E[]) new Object[capacity];
} /**
* 往index位置添加元素
*
* @param index 索引下标
* @param element 元素
*/
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacity(size + 1);
for (int i = size; i > index; i--) {
elements[i] = elements[i - 1];
}
elements[index] = element;
size++;
} /**
* 返回index位置对应的元素
*
* @param index 索引下标
* @return
*/
public E get(int index) {
rangeCheck(index);
return elements[index];
} /**
* 设置index位置的元素
*
* @param index 索引下标
* @param element 元素
* @return 原来的元素
*/
public E set(int index, E element) {
rangeCheck(index);
E oldElement = elements[index];
elements[index] = element;
return oldElement;
} /**
* 删除index位置对应的元素
*
* @param index 索引下标
* @return 删除的元素值
*/
public E remove(int index) {
rangeCheck(index);
E result = elements[index];
for (int i = index + 1; i < size; i++) {
elements[i - 1] = elements[i];
}
elements[--size] = null;
return result;
} /**
* 删除对象
*
* @param element 对象
*/
public void remove(E element) {
remove(indexOf(element));
} /**
* 查看元素的位置
*
* @param element 元素
* @return
*/
@SuppressWarnings("null")
public int indexOf(E element) {
if (element == null) {
for (int i = 0; i < size; i++) {
if (elements[i] == null)
return i;
}
} else {
for (int i = 0; i < size; i++) {
if (element.equals(elements[i]))
return i;
}
} return ELEMENT_NOT_FOUND;
} /**
* 清除所有元素
*/
public void clear() {
for (int i = 0; i < size; i++) {
elements[i] = null;
}
size = 0;
} @Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("size=").append(size).append(",[");
for (int i = 0; i < size; i++) {
// 方式一(推荐)
if (i > 0) {
stringBuilder.append(",");
}
stringBuilder.append(elements[i]);
// 方式二(不推荐)
// if (i!=size-1) {
// stringBuilder.append(",");
// }
}
stringBuilder.append("]");
return stringBuilder.toString();
} /**
* 保证要有capacity的容量
*
* @param capacity 容量
*/
private void ensureCapacity(int capacity) {
int oldCapacity = elements.length;
if (oldCapacity >= capacity)
return;
// 新容量为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
@SuppressWarnings("unchecked")
E[] newElements = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
elements = newElements;
System.out.print("容量从" + oldCapacity + "扩展为" + newCapacity + "\n");
}
}

MyLinkedList.java

package com.cyb;

public class MyLinkedList<E> extends AbstractMyList<E> {
private Node<E> first; @Override
public void clear() {
size = 0;
first = null;
} @Override
public void add(int index, E element) {
if (index==0) {
first=new Node<E>(element, first);
}
else {
Node<E> prev = node(index-1);
prev.next=new Node<E>(element, prev.next);
}
size++;
} @Override
public E get(int index) {
// TODO Auto-generated method stub
return node(index).element;
} @Override
public E set(int index, E element) {
Node<E> node = node(index);
E old = node.element;
node.element = element;
return old;
} @Override
public E remove(int index) {
Node<E> node=first;
if (index==0) {
first=first.next;
}
else {
Node<E> prev = node(index-1);
node=prev.next;
prev.next=node.next;
}
size--;
return node.element;
} @Override
public int indexOf(E element) {
if (element == null) {
Node<E> node=first;
for (int i = 0; i < size; i++) {
if (node.element == null)
return i;
node=node.next;
}
} else {
Node<E> node=first;
for (int i = 0; i < size; i++) {
if (element.equals(node.element))
return i;
node=node.next;
}
}
return ELEMENT_NOT_FOUND;
} /**
* 获取index位置对应的节点对象
*
* @param index 索引下标
* @return
*/
private Node<E> node(int index) {
rangeCheck(index);
Node<E> node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("size=").append(size).append(",[");
Node<E> node=first;
for (int i = 0; i < size; i++) {
// 方式一(推荐)
if (i > 0) {
stringBuilder.append(",");
}
stringBuilder.append(node.element);
// 方式二(不推荐)
// if (i!=size-1) {
// stringBuilder.append(",");
// }
node=node.next;
}
stringBuilder.append("]");
return stringBuilder.toString();
} private class Node<E> {
E element;
Node<E> next; public Node(E element, Node<E> next) {
this.element = element;
this.next = next;
}
}
}

Test.java(测试类)

package com.cyb;

public class Test {

    public static void main(String[] args) {
MyList<Integer> list=new MyLinkedList<Integer>();
list.add(10);
list.add(20);
list.add(30);
list.add(2, 21);
list.add(list.size(),55);
list.remove(0);
System.out.println(list);
}
}

项目结构图

推荐一个学习算法的可视化网站:https://visualgo.net/zh

动态数组的缩容

  如果内存使用比较紧张,动态数组有比较多的剩余空间,可以考虑进行缩容操作。

缩容规则 

  如:剩余空间占总容量的一半时,就进行缩容。

在remove方法中,添加一个缩容方法。

package com.cyb;

/**
* 自定义ArrayList数组,有动态缩容操作
*
* @author chenyanbin
*
*/
public class MyArrayList2<E> extends AbstractMyList<E> { /**
* 所有元素
*/
private E[] elements;
private static final int DEFAULT_CAPACITY = 100; public MyArrayList2() {
this(DEFAULT_CAPACITY);
} @SuppressWarnings("unchecked")
public MyArrayList2(int capacity) {
capacity = (capacity < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capacity;
elements = (E[]) new Object[capacity];
} /**
* 往index位置添加元素
*
* @param index 索引下标
* @param element 元素
*/
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacity(size + 1);
for (int i = size; i > index; i--) {
elements[i] = elements[i - 1];
}
elements[index] = element;
size++;
} /**
* 返回index位置对应的元素
*
* @param index 索引下标
* @return
*/
public E get(int index) {
rangeCheck(index);
return elements[index];
} /**
* 设置index位置的元素
*
* @param index 索引下标
* @param element 元素
* @return 原来的元素
*/
public E set(int index, E element) {
rangeCheck(index);
E oldElement = elements[index];
elements[index] = element;
return oldElement;
} /**
* 删除index位置对应的元素
*
* @param index 索引下标
* @return 删除的元素值
*/
public E remove(int index) {
rangeCheck(index);
E result = elements[index];
for (int i = index + 1; i < size; i++) {
elements[i - 1] = elements[i];
}
elements[--size] = null;
trim();
return result;
} /**
* 删除对象
*
* @param element 对象
*/
public void remove(E element) {
remove(indexOf(element));
} /**
* 查看元素的位置
*
* @param element 元素
* @return
*/
@SuppressWarnings("null")
public int indexOf(E element) {
if (element == null) {
for (int i = 0; i < size; i++) {
if (elements[i] == null)
return i;
}
} else {
for (int i = 0; i < size; i++) {
if (element.equals(elements[i]))
return i;
}
} return ELEMENT_NOT_FOUND;
} /**
* 清除所有元素
*/
public void clear() {
for (int i = 0; i < size; i++) {
elements[i] = null;
}
size = 0;
} @Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("size=").append(size).append(",[");
for (int i = 0; i < size; i++) {
// 方式一(推荐)
if (i > 0) {
stringBuilder.append(",");
}
stringBuilder.append(elements[i]);
// 方式二(不推荐)
// if (i!=size-1) {
// stringBuilder.append(",");
// }
}
stringBuilder.append("]");
return stringBuilder.toString();
} /**
* 保证要有capacity的容量
*
* @param capacity 容量
*/
private void ensureCapacity(int capacity) {
int oldCapacity = elements.length;
if (oldCapacity >= capacity)
return;
// 新容量为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
@SuppressWarnings("unchecked")
E[] newElements = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
elements = newElements;
System.out.print("容量从" + oldCapacity + "扩展为" + newCapacity + "\n");
} /**
* 缩容
*/
private void trim() {
int capacity = elements.length;
int newCapacity = capacity >> 1;
if (size > newCapacity || capacity <= DEFAULT_CAPACITY)
return; E[] newElements = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
elements = newElements;
}
}

Java 代码实现链表的更多相关文章

  1. Java实现单链表的各种操作

    Java实现单链表的各种操作 主要内容:1.单链表的基本操作 2.删除重复数据 3.找到倒数第k个元素   4.实现链表的反转   5.从尾到头输出链表 6.找到中间节点 7.检测链表是否有环 8.在 ...

  2. 只用120行Java代码写一个自己的区块链

    区块链是目前最热门的话题,广大读者都听说过比特币,或许还有智能合约,相信大家都非常想了解这一切是如何工作的.这篇文章就是帮助你使用 Java 语言来实现一个简单的区块链,用不到 120 行代码来揭示区 ...

  3. 如何在Android上编写高效的Java代码

    转自:http://www.ituring.com.cn/article/177180 作者/ Erik Hellman Factor10咨询公司资深移动开发顾问,曾任索尼公司Android团队首席架 ...

  4. 斐波那契堆(Fibonacci heap)原理详解(附java代码实现)

    前言 斐波那契堆(Fibonacci heap)是计算机科学中最小堆有序树的集合.它和二项式堆有类似的性质,但比二项式堆有更好的均摊时间.堆的名字来源于斐波那契数,它常用于分析运行时间. 堆结构介绍 ...

  5. 数据结构-平衡二叉树 旋转过程平衡因子分析 c和java代码实现对比

    平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且 ...

  6. 消灭 Java 代码的“坏味道”

    消灭 Java 代码的“坏味道” 原创: 王超 阿里巴巴中间件 昨天 导读 明代王阳明先生在<传习录>谈为学之道时说: 私欲日生,如地上尘,一日不扫,便又有一层.着实用功,便见道无终穷,愈 ...

  7. JAVA数据结构——单链表

    链表:一. 顺序存储结构虽然是一种很有用的存储结构,但是他有如下几点局限性:1. 因为创造线性表的时候已经固定了空间,所以当需要扩充空间时,就需要重新创建一个地址连续的更大的存储空间.并把原有的数据元 ...

  8. java实现单链表的增删改以及排序

    使用java代码模拟单链表的增删改以及排序功能 代码如下: package com.seizedays.linked_list; public class SingleLinkedListDemo { ...

  9. 从 Java 代码到 Java 堆

    本文将为您提供 Java 代码内存使用情况的深入见解,包括将 int 值置入一个 Integer 对象的内存开销.对象委托的成本和不同集合类型的内存效率.您将了解到如何确定应用程序中的哪些位置效率低下 ...

随机推荐

  1. Ant Design中getFieldDecorator方法的特殊用法(小bug)

    记录Ant Design中getFieldDecorator方法的特殊的一个用法 了解Ant Design表单的小伙伴都知道,getFieldDecorator在大部分情况下是用来绑定一个控件的,即像 ...

  2. 大量SQL的解决方案——sdmap

    大量SQL的解决方案--sdmap 最近看到群里面经常讨论大型应用中SQL的管理办法,有人说用EF/EF Core,但很多人不信任它生成SQL的语句:有人说用Dapper,但将SQL写到代码中有些人觉 ...

  3. docker命令总结(二)

    上次只是给大家把命令的作用以及简单使用列出来了(大家可以查看:docker命令总结(一)),那这篇文章会详细介绍每条命令的参数,命令比较多建议大家使用搜索,进行查看 search docker sea ...

  4. 【一起学源码-微服务】Hystrix 源码二:Hystrix核心流程:Hystix非降级逻辑流程梳理

    说明 原创不易,如若转载 请标明来源! 欢迎关注本人微信公众号:壹枝花算不算浪漫 更多内容也可查看本人博客:一枝花算不算浪漫 前言 前情回顾 上一讲我们讲了配置了feign.hystrix.enabl ...

  5. 重拾c++第一天(1):环境配置

    时过多年,c++基本不记得了,故在此记录相关重拾记录. 学习语言第一步当然是环境配置了(笑),由于暂无用c++进行大型项目开发的需求,所以先下载dev进行过渡. 安装过程非常简单,值得注意的是配置时选 ...

  6. selenium webdriver从安装到使用(python语言),显示等待和隐性等待用法,切换窗口或者frame,弹框处理,下拉菜单处理,模拟鼠标键盘操作等

    selenium的用法 selenium2.0主要包含selenium IDE 和selenium webDriver,IDE有点类似QTP和LoadRunner的录制功能,就是firefox浏览器的 ...

  7. Activiti 启动事件(Start Event)

    Activiti 启动事件(Start Event) 作者:Jesai 生活里,没有容易二字,忧伤是一种本能,而微笑是一种能力 版权所有,未经允许,禁止引用.如需引用,请注明出处. 前言: 启动事件是 ...

  8. ASP.NET 开源导入导出库Magicodes.IE 导出Pdf教程

    基础教程之导出Pdf收据 说明 本教程主要说明如何使用Magicodes.IE.Pdf完成Pdf收据导出 要点 导出PDF数据 自定义PDF模板 导出单据 如何批量导出单据 导出特性 PdfExpor ...

  9. 洛谷 P5424 [USACO19OPEN]Snakes

    题目链接 题目描述 传说,数千年前圣帕特里克消灭了哞尔兰所有的蛇.然而,蛇们现在卷土重来了!圣帕特里克节是在每年的3月17日,所以Bessie要用彻底清除哞尔兰所有的蛇来纪念圣帕特里克. Bessie ...

  10. 安装xpath helper

    1.下载 版本是:2.02的 链接:https://pan.baidu.com/s/1YdyTbWElL904EMQ-9Ougnw 提取码:bxxa 2.无效安装的解决方案 参考链接:https:// ...