经过使用数组,能够存储一连串的数据java
在java中,能够存储全部的基本类型以及对象类型。node
可是若是在代码中,须要频繁对数组中的元素进行添加和删除,特别是从数组的头部进行添加和删除,就会有以下的问题:数组
//初始化一个数组
int[] a=new int[10];
a[0]=0;
a[1]=1;
a[2]=2;
//为了方便,使用currentSize来表示数组实际使用了多少
index=3;
//从头部插入一个元素-1,会使用以下方法
if(currentSize<10){
for(int i=currentSize;i>0;i--){
a[i]=a[i-1];
}
a[0]=-1;
}
//以上操做就是先把原先存在的数据日后移动,而后再插入头部
//当从头部删除一个元素时,使用方法以下
if(currentSize>0){
for(int i=0;i<currentSize;i++){
a[i]=a[i+1];
}
}
//以上操做就是把后面的元素往前移动
复制代码
从代码能够看出,对数组的插入和删除操做麻烦,若是数组的容量很是大的话,那么循环次数将很是多。编辑器
还有一个问题就是,当数组已存储的元素个数达到初始化的容量,若要继续添加元素,就须要对数组进行扩容。以下代码工具
int[] a=new int[2];
a[0]=0;
a[1]=1;
//此时数组已经达到最大数量,须要进行扩容。
int[] b=new int[a.length*2];
for(int i=0;i<a.length;i++){
b[i]=a[i];
}
a=b;
//此时数组a的容量就扩大到原来的两倍
复制代码
为了不使用数组带来的插入和删除的开销,须要保证元素能够不在内存地址上进行连续存储,不然添加或删除一个元素就可能须要总体移动。这是咱们就以使用链表来存储数据。this
链表由一系列节点组成,这些节点在内存中不必定相连。在最简单的链表中,每个节点均包含数据元素和该数据元素的后继的指针,将其称之为next。最后一个元素的next指向null。spa
如图: debug
//链表节点实现
class Node {
//使用Object类型,让节点可以保存任意类型的数据
private Object data;
private Node next;
public Node(Object data) {
this.data = data;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
//链表使用
public class Test {
public static void main(String[] args) {
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
node1.setNext(node2);
node2.setNext(node3);
node3.setNext(null);
//这样的链表就和数组 int[] a=new int[]{1,2,3}差很少,因为node3的后继不存在,因此node3指向null
}
}
复制代码
咱们能够经过intellij编辑器的断点进行查看: 3d
关系就是node1->node2->node3->null指针
通常的,咱们会为链表设置一个表头,它不存储数据,可是指向第一个元素
package list; class Node { //使用Object类型,让节点可以保存任意类型的数据 private Object data; private Node next; public Node() { } public Node(Object data) { this.data = data; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public Node getNext() { return next; } public void setNext(Node next) { this.next = next; } } public class Test { public static void main(String[] args) { //声明表头 Node head=new Node(); Node node1 = new Node(1); Node node2 = new Node(2); Node node3 = new Node(3); //直接指向node1,里面没有存储数据 head.setNext(node1); node1.setNext(node2); node2.setNext(node3); node3.setNext(null); } } 复制代码
链表的插入很简单,好比要想n节点插入到s节点的后面,首先对链表进行遍历,找到s节点后,先让n.next=s.next,而后让s.next=n
public class Test {
public static void main(String[] args) {
Node head = new Node();
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
head.setNext(node1);
node1.setNext(node2);
node2.setNext(node3);
node3.setNext(null);
//声明一个node4
Node node4 = new Node(4);
//要想获得某个指定的节点,就得对链表进行遍历,若是到了某个节点,其next指向为null,说明整个链表都遍历完毕,不存在指定的节点元素,全部可使用while循环进行遍历
Node node = head;
while ((node = node.getNext()) != null) {
//等于2的时候,就是找到了节点node2
if (node.getData().equals(2)) {
//先让新节点node4指向node2的下一节点,也就是node3
node4.setNext(node2.getNext());
//而后让node2指向新节点node4
node2.setNext(node4);
//跳出循环
break;
}
}
}
}
复制代码
使用debug工具进行查看:
删除和插入相似,好比要想删除节点n,首先对链表进行遍历,找到s节点,知足s.next=n,而后让s.next=n.next ,n.ndex=null,节点n会因为虚拟机的垃圾回收机制被自动回收
public class Test {
public static void main(String[] args) {
Node head = new Node();
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
head.setNext(node1);
node1.setNext(node2);
node2.setNext(node3);
node3.setNext(null);
//要想获得某个指定的节点,就得对链表进行遍历,若是到了某个节点,其next指向为null,说明整个链表都遍历完毕,不存在指定的节点元素,全部可使用while循环进行遍历
Node node = head;
while ((node = node.getNext()) != null) {
//节点的next.data等于2的时候,就找到了须要被删除节点的前驱
if (node.getNext().getData().equals(2)) {
Node deleteNode = node.getNext();
//先让前驱指向后继
node.setNext(deleteNode.getNext());
//而后把删除节点的后继指向null
deleteNode.setNext(null);
//跳出循环
break;
}
}
}
}
复制代码
debug查看
能够看到,该链表中再也不包含2
总的来讲,数组和链表使用频率都大,下面总结下各自的优势和缺点
查询快,由于有下标
缺点
由于链表中的节点不是连续的,因此想要获取某个元素的时候须要对链表进行遍历和判断
须要常常添加和删除元素时,用链表。元素不会常常变更,或者查询频率较高,用数组