集合框架
ArrayList与LinkedList
- 相同点:
- 都是List集合的常用的实现类。
- 对集合中的元素操作的方法基本一致。
- 不同点:
- ArrayList底层实现是数组, 使用数组这种数据结构进行数据的存储。 LinkedList底层实现是双链表, 使用双链表这种数据结构进行数据的存储。
ArrayList与LinkedList的使用场景:
- 如果对集合中的元素, 增删操作不怎么频繁, 查询操作比较频繁。 使用ArrayList。
- 如果对集合中的元素, 增删操作比较频繁, 查询操作不怎么频繁。 使用LinkedList。
LinkedList与链表
链表
- 链表,其实是一种比较常见的数据结构。 增删效率比较高, 查询效率比较低。
- 数据在链表中存储,是以节点为单位进行存储的。 节点之间在内存上是不连续的。 双向链表中的每一个节点, 除了记录了当前节点存储的元素之外, 还记录了上一个节点和下一个节点的地址。
模拟LinkedList中的方法
/**
* @Author 昊
* @Create 2020/4/20 18:24
* @Description
*/
public class One {
public static void main(String[] args) {
MyLinkedList<String> myLinkedList=new MyLinkedList<>();
myLinkedList.add("lily");
myLinkedList.add("lucy");
myLinkedList.add("tom");
myLinkedList.add("jim");
myLinkedList.add(1,"kelly");
myLinkedList.remove(1);
boolean b=myLinkedList.remove("lucy");
String s=myLinkedList.get(1);
int nub=myLinkedList.size();
boolean b2=myLinkedList.contains("lucy");
int index=myLinkedList.indexOf("lucy");
myLinkedList.set(3,"kelly");
System.out.println(myLinkedList);
myLinkedList.clear();
System.out.println(index);
System.out.println(b2);
System.out.println(nub);
System.out.println(s);
System.out.println(b);
System.out.println(myLinkedList);
}
}
//模拟LinkedList,并实现其中相关的方法
//主要是练习双向链表,因为LinkedList的底层实现是双向链表
class MyLinkedList<E>{
//链表中元素以节点的形式存储
//内部类,表示一个节点
private class Node{
//表示这个节点需要存储的元素
E element;
//下一个节点地址
Node next;
//上一个节点地址
Node previous;
public Node(E element){
this.element=element;
}
}
//用来描述首节点
private Node first;
//用来描述尾节点
private Node last;
//用来描述节点数量
private int count;
/**
* 向集合中添加元素
* @param element 需要添加的元素
*/
public void add(E element){
//1、实例化一个节点,用来存储这个元素
Node node = new Node(element);
//2、将这个节点链接到链表尾部
//2.1、若为空则该节点就作为头节点
//2.2、若不空则链接到尾部
if(count==0){
this.first=node;
}else{
this.last.next=node;
node.previous=this.last;
}
this.last=node;
count++;
}
/**
* 在指定索引位置之前添加节点
* @param index 指定下标
* @param element 要插入的元素
*/
public void add(int index,E element){
//初始化一个节点
Node node=new Node(element);
//如果在头部插入
if(index==0){
this.first.previous=node;
node.next=this.first;
this.first=node;
}
//插入尾部
else if(index==count){
this.last.next=node;
node.previous=this.last;
this.last=node;
}else {
Node target=getNode(index);
node.previous=target.previous;
target.previous.next=node;
node.next=target;
target.previous=node;
}
count++;
}
/**
* 通过下标获取指定位置的节点
* @param index 指定下标
* @return 下标对应的节点
*/
public Node getNode(int index){
//1、判断下标是否合法,不合法抛出异常
if(index<0||index>=count){
throw new IndexOutOfBoundsException("size()="+count+",index="+index);
}
//向下循环寻找节点
Node node=this.first;
for (int i = 0; i < index; i++) {
node=node.next;
}
return node;
}
/**
* 删除指定标的元素并将这个元素返回
* @param index 指定下标
* @return 被删除的元素
*/
public E remove(int index){
//找到index对应的节点
Node target=getNode(index);
//删除这个节点
removeNode(target);
return target.element;
}
/**
* 删除指定节点
* @param node 需要被删除的节点
*/
private void removeNode(Node node){
//当链表中只有一个节点时
if(count==1){
this.first=null;
this.last=null;
count--;
// return ;
}
//判断是否删除的是首节点
if(node==this.first){
//设置新的首节点
this.first=this.first.next;
//取消首节点与上一个节点的关联
this.first.previous=null;
this.first.next.previous=null;
}
//如果删除的是尾节点
else if(node==this.last){
//设置新的尾节点
this.last=this.last.previous;
//取消尾节点与下一个节点的关联
this.last.previous.next=null;
this.last.previous.next=null;
}else{
node.previous.next=node.next;
node.next.previous=node.previous;
}
count--;
}
/**
* 删除链表中指定的元素,若删除成功则返回true,否则返回false
* @param element 要删除的元素
* @return 删除成功返回true,否则返回false
*/
public boolean remove(E element){
boolean flag=true;
Node node=this.first;
for(int i=0;i<count;i++){
if(node.element==element){
flag=false;
break;
}else {
node= node.next;
}
}
return flag;
}
/**
* 清空链表中所有的元素
*/
public void clear(){
Node node=this.first;
for (int i = 0; i <count ; i++) {
if(node!=null){
node=node.next;
node.previous.next=null;
node.previous=null;
}
this.last=this.first=null;
count=0;
}
}
/**
* 修改指定位置的元素,并返回被覆盖的元素
* @param index 知道下标
* @param element 新元素
* @return 被修改的元素
*/
public E set(int index,E element){
// 1. 判断下标的合法性
if (index < 0 || index >= count) {
throw new IndexOutOfBoundsException("size() = " + count + ", index = " + index);
}
//获得指定下标的节点
Node target=getNode(index);
//获得下标位置节点的元素
E res= target.element;
//修改元素
target.element=element;
return res;
}
/**
* 获得指定位置的元素
* @param index 指定位置
* @return 指定位置的元素
*/
public E get(int index){
//获得指定位置的节点
Node target=getNode(index);
E res=target.element;
return res;
}
/**
*
* @return 返回集合元素个数
*/
public int size(){
return count;
}
/**
* 检查集合中是否含有指定元素
* @param element 指定元素
* @return 若存在返回true,否则返回false
*/
public boolean contains(E element){
boolean flag=false;
Node node=this.first;
for (int i = 0; i < count; i++) {
if(node.element!=element){
node=node.next;
}else {
flag=true;
break;
}
}
return flag;
}
/**
* 返回指定元素第一次出现的下标
* @param element 指定元素
* @return 若存在则返回指定元素第一次出现的下标,若不存在返回-1
*/
public int indexOf(E element){
int index=-1;
Node node=this.first;
for(int i=0;i<count;i++){
if(node.element!=element){
node=node.next;
}else {
index=i;
break;
}
}
return index;
}
@Override
public String toString() {
if(count==0){
return "[]";
}
StringBuilder stringBuilder=new StringBuilder("[");
Node node=this.first;
for(int i=0;i<count;i++){
stringBuilder.append(node.element);
stringBuilder.append(",");
node=node.next;
}
stringBuilder.replace(stringBuilder.length()-1,stringBuilder.length(),"]");
return stringBuilder.toString();
}
}