基于Java的ArrayList和LinkedList的实现与总结
一、定义MyList接口,包含列表常见方法:
import java.util.Iterator; /**
* 线性表(列表)的接口定义
*/
public interface MyList<T> extends Iterator<T> { /** 新增一个元素 */
void add(T element); /** 删除相同元素 */
void delete(T element); /** 根据索引删除元素 */
void delete(int index); /**
* 将指定索引位置的元素替换成新元素
*
* @param index
* @param newElement
*/
void update(int index, T newElement); /**
* 当前列表中是否含有target这个元素
*
* @param target
* @return
*/
boolean contains(T target); /**
* 返回指定索引处的元素
*
* @param index
* @return
*/
T at(int index); /**
* 查找element的索引,如果没有返回-1
*
* @param element
* @return
*/
int indexOf(T element); }
二、实现ArrayList类:
/**
* 用顺序存储(数组)方式来实现列表
*/
public class MyArrayList<T> implements MyList<T> {
private T[] elements;// 真正存储元素的底层结构 private int size = 0;// 元素个数 private int capacity = 10;// 容量 public MyArrayList(int capacity) {
this.capacity = capacity;
elements = (T[]) new Object[capacity];
} public MyArrayList() {
elements = (T[]) new Object[capacity];
} @Override
public void add(T element) {
if (size == capacity) {// 扩容
capacity *= 2;// 增加一倍的容量
T[] newArr = (T[]) new Object[capacity];// 新建一个数组
for (int i = 0; i < size; i++) {
newArr[i] = elements[i];
}
elements = newArr;// 把旧的那个柜子扔掉
}
elements[size++] = element;
} @Override
public void delete(T element) {
int index = indexOf(element);
if (index >= 0) {
delete(index);
}
} @Override
public void delete(int index) {
// 重新调整空间
for (int i = index; i < size - 1; i++) {
elements[i] = elements[i + 1];
}
elements[size - 1] = null;
size--;
} @Override
public void update(int index, T newElement) {
elements[index] = newElement;
} @Override
public boolean contains(T target) {
return indexOf(target) >= 0;
} @Override
public T at(int index) {
return elements[index];
} @Override
public int indexOf(T element) {
for (int i = 0; i < size; i++) {
if (elements[i].equals(element)) {
return i;
}
}
return -1;
} @Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < size; i++) {
sb.append(elements[i] + (i == size - 1 ? "" : " , "));
}
sb.append("]");
return sb.toString();
} //
@Override
public boolean hasNext() {
return false;
} @Override
public T next() {
return null;
}
}
三、链表结点类:
/*节点*/
public class ListNode<T> {
T data;
ListNode<T> pre;
ListNode<T> next; // next 实际存的是下一个节点 重要理解 public ListNode(T data) {
this.data = data;
} public T getData() {
return data;
} public ListNode<T> getPre() {
return pre;
} public void setNext(ListNode<T> next) {
this.next = next;
} public void setPre(ListNode<T> pre) {
this.pre = pre;
} public ListNode<T> getNext() {
return next;
}
}
四、单链表实现:
public class SingleLinkedList<T> implements MyList<T> {
private ListNode<T> first; // 头节点 head
private ListNode<T> last; // 尾节点
private int size; @Override
public void add(T element) {
if (first == null) {
first = new ListNode(element);
last = first;
} else {
last.next = new ListNode(element); // next 实际存的是下一个节点 重要理解
last = last.next;
}
size++;
} @Override
public void delete(T element) {
ListNode p = first;
ListNode pre = null;
while (p != null) {
if (p.data.equals(element)) {
if (p == first)
first = first.next;
else
pre.next = p.next;
size--;
break;// 注意这里
}
pre = p;
p = p.next;
}
} // 链表删除
// 参数为索引
@Override
public void delete(int index) {
if (index < 0 || index >= size) {
return;// 啥也不干
}
int i = 0;// 指针指向的节点的索引
ListNode p = first;
ListNode pre = null; while (p != null) {
if (i == index) {
if (p == first)
first = first.next;
else
pre.next = p.next;
break;// 注意这里
}
pre = p;
p = p.next;
i++;
}
size--;
} @Override
public void update(int index, T newElement) {
if (index < 0 || index >= size) {
return;// 啥也不干
}
int i = 0;// 指针指向的节点的索引
ListNode p = first; while (p != null) {
if (i == index) {
p.data = newElement;
}
p = p.next;
i++;
}
} @Override
public boolean contains(T target) {
ListNode p = first;
while (p != null) {
if (p.data.equals(target)) {
return true;
}
p = p.next;
}
return false;
} // 返回索引所在的data
@Override
public T at(int index) {
if (index < 0 || index >= size) {
return null;
}
int i = 0;// 指针指向的节点的索引
ListNode<T> p = first; while (p != null) {
if (i == index) {
return p.data;
}
p = p.next;
i++;
}
return null;
} @Override
public int indexOf(T element) {
int i = 0;// 指针指向的节点的索引
ListNode p = first; while (p != null) {
if (p.data.equals(element)) {
return i;
}
p = p.next;
i++;
}
return -1;
} @Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
ListNode p = first;
while (p != null) {
sb.append(p.data);
if (p.next != null)
sb.append(",");
p = p.next;
}
sb.append("]");
return sb.toString();
} @Override
public boolean hasNext() {
return false;
} @Override
public T next() {
return null;
}
}
五、双链表实现:
import java.util.Iterator; public class DoubleLinkedList<T> implements MyList<T> { // 多了两个没有数据的头节点和尾节点 哑元
protected ListNode<T> first = new ListNode(null);
protected ListNode<T> last = new ListNode(null);
protected int size; public int getSize() {
return size;
} public DoubleLinkedList() {
first.next = last;
last.pre = first;
} @Override
public void add(T element) {
ListNode<T> newNode = new ListNode(element);
last.pre.next = newNode;
newNode.next = last;
newNode.pre = last.pre;
last.pre = newNode;
size++;
} @Override
public void delete(T element) {
ListNode<T> p = first.next;
while (p != last) {
if (p.data.equals(element)) {
p.pre.next = p.next;
p.next.pre = p.pre;
p.next = null;
p.pre = null;
size--;
break;
}
p = p.next;
}
} @Override
public void delete(int index) {
if (index < 0 || index >= size) {
return;// 啥也不干
}
int i = 0;// 指针指向的节点的索引
ListNode p = first.next; while (p != last) {
if (i == index) {
p.pre.next = p.next;
p.next.pre = p.pre;
p.next = null;
p.pre = null;
size--;
break;// 注意这里
}
p = p.next;
i++;
}
} @Override
public void update(int index, T newElement) {
if (index < 0 || index >= size) {
return;// 啥也不干
}
int i = 0;// 指针指向的节点的索引
ListNode p = first.next; while (p != last) {
if (i == index) {
p.data = newElement;
}
p = p.next;
i++;
}
} @Override
public boolean contains(T target) {
ListNode p = first.next;
while (p != last) {
if (p.data.equals(target)) {
return true;
}
p = p.next;
}
return false;
} @Override
public T at(int index) {
if (index < 0 || index >= size) {
return null;
}
int i = 0;// 指针指向的节点的索引
ListNode<T> p = first.next; while (p != last) {
if (i == index) {
return p.data;
}
p = p.next;
i++;
}
return null;
} @Override
public int indexOf(T element) {
int i = 0;// 指针指向的节点的索引
ListNode<T> p = first.next; while (p != last) {
if (p.data.equals(element)) {
return i;
}
p = p.next;
i++;
}
return -1;
} @Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
ListNode p = first.next;
while (p != last) {
sb.append(p.data);
if (p.next != last)
sb.append(",");
p = p.next;
}
sb.append("]");
return sb.toString();
} // 实现迭代器 MyList 继承Iterator<T>这个接口
private ListNode now = first; @Override
public boolean hasNext() {
return now.next != last;
} @Override
public T next() {
ListNode<T> next = now.next;
now = now.next;
return next.data;
}
}
六、Java ListApi的基本使用:
import java.util.*; public class ListApiDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list = new LinkedList<>();
list.add("adnda");
list.add("xyz");
list.add("def");
list.remove("");
// ...... Collections.sort(list); System.out.println(list);
List<Student> list1 = new ArrayList<>();
list1.add(new Student("zhangsan", 10));
list1.add(new Student("lsii", 20));
list1.add(new Student("wangwu", 40));
list1.add(new Student("wangsu", 30)); Collections.sort(list1, (o1, o2) -> {
return o1.getAge() - o2.getAge();
}); System.out.println(list1); for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
} System.out.println("===============");
for (Student stu : list1) {
System.out.println(stu);
}
System.out.println("++++++++++++++++++++");
Iterator<Student> iterator = list1.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
class Student{
String name;
int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} }
七、ArrayList和LinkedList总结:
1、ArrayList和LinkedList都是实现了List接口的容器类,用于存储一系列的对象引用。他们都可以对元素的增删改查进行操作。
2、ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
3、对ArrayList和LinkedList的空间复杂度而言,对 ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Node对象。ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间 。
4、对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针。 ArrayList可以根据索引直接算出地址。
5、在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。
6、对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。对于查找和修改操作,如果按照索引查找和修改,ArrayList优于LinedList,如果按照内容来进行查找和修改,ArrayList和LinedList所花费的时间差不多。
7、LinkedList不支持高效的随机元素访问。 比如二分查找就是才有的随机策略,就不适合采用LinkedList,适合ArrayList。
可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在一列数据的前面或中 间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。 所以,如果只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用Vector或ArrayList都可以。如果是对其它指定位置的插入、删除操作,最好选择LinkedList。
注意:next 实际存的是下一个节点 个人重要理解。
基于Java的ArrayList和LinkedList的实现与总结的更多相关文章
- Java中ArrayList与LinkedList的区别
Java中ArrayList与LinkedList的区别 一般大家都知道ArrayList和LinkedList的区别: 1. ArrayList的实现是基于数组,LinkedList的实现是基于双向 ...
- java中ArrayList 和 LinkedList 有什么区别
转: java中ArrayList 和 LinkedList 有什么区别 ArrayList和LinkedList都实现了List接口,有以下的不同点:1.ArrayList是基于索引的数据接口,它的 ...
- Java 集合 ArrayList和LinkedList的几种循环遍历方式及性能对比分析 [ 转载 ]
Java 集合 ArrayList和LinkedList的几种循环遍历方式及性能对比分析 @author Trinea 原文链接:http://www.trinea.cn/android/arrayl ...
- Java中arraylist和linkedlist源代码分析与性能比較
Java中arraylist和linkedlist源代码分析与性能比較 1,简单介绍 在java开发中比較经常使用的数据结构是arraylist和linkedlist,本文主要从源代码角度分析arra ...
- Java基础-ArrayList和LinkedList的区别
大致区别: 1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. 2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为Lin ...
- Java中ArrayList和LinkedList差别
一般大家都知道ArrayList和LinkedList的大致差别: 1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. 2.对于随机訪问get和set.A ...
- JAVA中ArrayList与LinkedList的区别以及对应List使用foreach与使用下标遍历的效率问题
近期在做一个对接京东的电商平台,所以对各个地方的效率考虑的比较多,今天深挖了一下ArrayList与LinkedList的区别以及对应List使用foreach与使用下标遍历的效率问题,首先说一下两种 ...
- Java基础——ArrayList与LinkedList(一)
一.定义 ArrayList和LinkedList是两个集合类,用于储存一系列的对象引用(references). 引用的格式分别为: ArrayList<String> list = n ...
- Java中ArrayList和LinkedList区别 时间复杂度 与空间复杂度
一般大家都知道ArrayList和LinkedList的大致区别: 1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. 2.对于随机访问 ...
随机推荐
- mac下Android开发环境的配置
近似一天的时间,终于把Android环境配置好了. 总结:主要问题在于android的网站是国外,下载东西的时候需要vpn才可以.所以会出现各种各样的问题. 环境:Android Studio + S ...
- linux yum提示Loaded plugins: fastestmirror, security错误的解决方法
别听网上的,先检查自己是不是打错了.........我就是打错了一个横杆搞了一个多小时 具体: 如图这种,长横杆 修改后结果: 所以在不知情的情况之下千万不要乱改东西,先检查代码是否有误 题外话: = ...
- 使用Django的时候,页面请求正常,也没有报任何错误,甚至连警告都没有的情况下,页面却还是原地不动或者闪一下或者无限显示加载动画的情况下的解决办法
这个问题描述比较笼统,但根据我目前遇到过两种情况来看,似乎都比较重要而且实用,所以打算分别讲述一下. 说明:Django的版本是Django2.0 第一种:URL配置错误 页面闪一下,却原地不动,可能 ...
- 小秘书智能app登录
项目流程 项目图解 登录逻辑 建立项目 前端: 后端: Flask 数据库: Mongo 分工: 我负责的:
- brew本地安装包
brew --cache # 输出本地缓存 一般位置 ~/Library/Caches/Homebrew # 将下载下来文件mv到缓存路径 download目录 # 重命名成没有下载下来的文件名 xx ...
- jq实现遮罩等待转圈
function Show_TopDiv(msg,msg_Width,msg_Height) { var titleheight = "22px"; // 提示窗口标题高度 var ...
- Core在类中注入
private readonly IHttpClientFactory _iHttpClientFactory; public static NetHelper Get = new NetHelper ...
- C++构造函数和析构函数的调用顺序
1.构造函数的调用顺序 基类构造函数.对象成员构造函数.派生类本身的构造函数 2.析构函数的调用顺序 派生类本身的析构函数.对象成员析构函数.基类析构函数(与构造顺序正好相反) 3.特例 局部对象,在 ...
- main方法启动spring
main方式读取spring配置.main方法启动spring/ 有时候只想写一下简单的测试用一下. 新建一个maven项目 依赖pom <?xml version="1.0" ...
- notes for python简明学习教程(2)
方法是只能被该类调用的函数 print函数通常以换行作为输出结尾 字典的items方法 返回的是元组列表 即列表中的每个元素都是元组 切片左闭右开 即开始位置包含在切片中 结束位置不在 每一个对象都能 ...