温馨提示: 在遍历如LinkedList等链表结构的集合时 请使用迭代器遍历,而不是for{list.get()} for的时间复杂度是O(n²) 迭代器遍历是O(n)
测试代码:
public void test02(){
List<Integer> list = new LinkedArrayClass();
list.add(1);
list.add(3);
list.add(2);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
Iterator<Integer> iterator = list.iterator();
System.out.println(iterator.next());
iterator.remove();
System.out.println(iterator.next());
for (int j = 0; j < list.size(); j++) {
System.out.println(list.get(j));
}
}
链表代码:
package com.yeyu.study.day02.linked;
import java.util.*;
import java.util.function.Consumer;
/**
* @description: 自定义集合 数据结构为单向链表
* @author: ganzj
* @create: 2021-03-27 22:03
*/
public class LinkedArrayClass<Y> implements List<Y>{
private int size = 0; //集合大小 计数器
private Node<Y> first; //链表开始的节点
private Node<Y> last; //链表最后一个节点
/**
* 引用一个变量做计数器 记录链表的大小
* @return
*/
@Override
public int size() {
return this.size;
}
/**
* 判断是否是一个空集合 判断计数器是否等于0即可
* @return
*/
@Override
public boolean isEmpty() {
return size==0;
}
/**
* 根据传参 判断当前集合中 是否存在该值
* @param o 需要判断的值
* @return
*/
@Override
public boolean contains(Object o) {
return indexOf(o)>0; //调用indexOf方法 判断下标大小即可得出是否存在
}
@Override
public Iterator<Y> iterator() {
return new Ite();
}
/**
* 内部类 实现迭代器 简单实现 没做扩展
*/
private class Ite implements Iterator{
private int index = 0;
private Node<Y> lastNode;
private Node<Y> next;
private int modNum;
Ite(){
next = first;
modNum = size;
}
@Override
public boolean hasNext() {
return index<size;
}
@Override
public Object next() {
if(modNum != size){
throw new RuntimeException("数据有改动,抛出异常");
}
index++;
lastNode = next;
next = next.next;
return lastNode.e;
}
@Override
public void remove() {
next = next.next;
lastNode.next = next;
modNum--;
size--;
}
/**
* 待补充
* @param action
*/
@Override
public void forEachRemaining(Consumer action) {
}
}
@Override
public Object[] toArray() {
Object[] result = new Object[size]; //创建一个等于集合长度的数组
int i = 0;
for (Node<Y> n = first; n != null; n = n.next) //遍历将集合的值传入数组
result[i++] = n.e;
return result;
}
/**
* JDK的文档写的是 : 以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 返回的数组的运行时类型是指定数组的运行时类型。
* 感觉是
* @param a
* @param <T>
* @return
*/
@Override
public <T> T[] toArray(T[] a) {
return null;
}
@Override
public boolean add(Y y) {
Node temp = last; //将记录的最后一个链表放入临时变量
last = new Node<Y>(y,null); //生成一个节点 记为最后一个节点
if(first == null){ //如果第一个节点为null则将此节点记录为第一个节点
first = last;
}else{
temp.next = last; //将临时变量的下一个节点指向last
}
size++; //计数器+1
return true;
}
/**
* 根据值删除节点
* @param o
* @return
*/
@Override
public boolean remove(Object o) {
if(first == null){ //判断first是否为null 如果是则链表为null 直接返回false
return false;
}
//判断传值是否为null 执行相应的比较方法 比较完返回Boolean
if(o == null ){
for (Node n = first; n!=null ; n=n.next){
if(n.e==null){
return true;
}
}
}else{
for (Node n = first; n!=null ; n=n.next){
if(o.equals(n.e)){
return true;
}
}
}
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
return false;
}
@Override
public boolean addAll(Collection<? extends Y> c) {
return false;
}
@Override
public boolean addAll(int index, Collection<? extends Y> c) {
return false;
}
@Override
public boolean removeAll(Collection<?> c) {
return false;
}
@Override
public boolean retainAll(Collection<?> c) {
return false;
}
/**
* 初始化
* 就不做遍历清除了 直接去掉first的引用等待GC回收
* 如果数据量大 或者其他业务需求比如有节点在被引用等 可以做循环清除每个节点的数据
*/
@Override
public void clear() {
first = null;
last = null;
size = 0;
}
/**
* 根据下标 获得值
* @param index
* @return
*/
@Override
public Y get(int index) {
checkIndexOutOf(index);
if(first == null){ //判断first是否为空 如果为空则直接返回
return null;
}
if(index ==0){ //如果是获取0的值 则直接返回first的值
return first.e;
}
int num = 0; //循环标志位
for (Node<Y> n = first; n!=null ; n=n.next,num++){ //循环到指定下标时 返回相应值
if(num == index){
return n.e;
}
}
return null;
}
/**
* 替换指定的下标的值
* @param index
* @param element
* @return
*/
@Override
public Y set(int index, Y element) {
checkIndexOutOf(index);
if(index ==0){ //如果是0则直接修改first的值
if(first ==null){ //如果first为null 则先实例化first再赋值
first = new Node<Y>(element,null);
return element;
}
Y temp = first.e;
first.e = element;
return temp;
}
int num = 1;
for (Node<Y> n = first.next; n!=null ; n=n.next,num++){ //循环赋值
if(num == index){
Y temp = n.e;
n.e = element;
return temp;
}
}
return null;
}
/**
* 将值插入到指定下标 后面的下标依次往后移1位
* @param index
* @param element
*/
@Override
public void add(int index, Y element) {
checkIndexOutOf(index);
if(index ==0){
if(first ==null){
first = new Node<Y>(element,null);
}
first.e = element;
}
int num = 1; //first以及比较过了 此处可以从1开始
for (Node<Y> n = first.next; n!=null ; n=n.next,num++){
if(num == index){
n.e = element;
}
}
}
/**
* 删除该列表中指定位置的元素。 将后续元素往前移1位 返回被删除的值
* @param index
* @return
*/
@Override
public Y remove(int index) {
checkIndexOutOf(index);
if(index ==0){
if(first ==null){
return null;
}
Y temp = first.e;
first = first.next;
return temp;
}
int num = 1; //first已经比较过了 此处可以从1开始
Node tempNode = null;
for (Node<Y> n = first.next; n!=null ; n=n.next,num++){
if(num == index){
Y temp = n.e;
if(num==1){
first.next = n.next;
}else{
tempNode.next = n.next;
}
return temp;
}
tempNode = n;
}
return null;
}
/**
* 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1
* @param o
* @return
*/
@Override
public int indexOf(Object o) {
int num = -1;
if(o != null){ //判断参数是否为null 比较方式不同 如果为null没有实例化调用equas方法 会抛出异常
for (Node n = first; n != null; n=n.next){ //循环 当指向的下一个节点为null时 代表是最后一个节点了 结束循环
num++;
if(o.equals(n.e)){ //如果发现有匹配到的值 则直接返回下标
return num;
}
}
}else{
for (Node n = first; n != null; n=n.next){ //循环 当指向的下一个节点为null时 代表是最后一个节点了 结束循环
num++;
if(n.e==null){ //如果包含null值 则直接返回下标;
return num;
}
}
}
return num;
}
/**
* 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
* @param o
* @return
*/
@Override
public int lastIndexOf(Object o) {
int num = 0;
int index = -1;
if(o != null){ //判断参数是否为null 比较方式不同 如果为null没有实例化调用equas方法 会抛出异常
for (Node n = first; n != null; n=n.next){ //循环 当指向的下一个节点为null时 代表是最后一个节点了 结束循环
num++;
if(o.equals(n.e)){ //如果发现有匹配到的值 则将当前下标赋值给index
index = num;
}
}
}else{
for (Node n = first; n != null; n=n.next){ //循环 当指向的下一个节点为null时 代表是最后一个节点了 结束循环
num++;
if(n.e==null){ //如果包含null值 则将当前下标赋值给index
index = num;
}
}
}
return index;
}
@Override
public ListIterator<Y> listIterator() {
return null;
}
@Override
public ListIterator<Y> listIterator(int index) {
return null;
}
@Override
public List<Y> subList(int fromIndex, int toIndex) {
LinkedArrayClass<Y> linkedArrayClass = new LinkedArrayClass<>();
int num = 0;
for (Node<Y> n = first.next; n!=null&&num>=fromIndex&&num<=toIndex; n=n.next,num++){
linkedArrayClass.add(n.e);
}
return linkedArrayClass;
}
/**
* 判断是否下标溢出
* @param index
* @return
*/
private void checkIndexOutOf(int index){
//判断索引是否为0 或则大于集合的总大小 抛出异常
if(index<0 || index>size){
throw new IndexOutOfBoundsException("下标溢出:"+index);
}
}
//内部类 链表结构 包含下一节点的单向链表结构
private class Node<Y>{
private Y e; //当前数据
private Node<Y> next; //下一节点数据
public Node(Y e, Node<Y> next) {
this.e = e;
this.next = next;
}
}
}