LinkList
数组是在连续的存储位置上存放对象引用,而链表则是将每个对象存放在单独的链接(link)中。每个链接还存放着序列中下一个链接的引用。在Java程序设计语言中,所有链表实际上都是双向链接的(doubly linked)——即每个链接还存放着其前驱的引用。
代码示例:
public class TestLinkedList {
@Test
void test01() {
LinkedList ll = new LinkedList();
ll.add(123);
ll.add(456);
ll.add(789);
ll.add(753);
ll.add(159);
ll.add(492);
System.out.println(ll.get(0));
System.out.println(ll.get(1));
System.out.println(ll.get(5));
System.out.println(ll.get(55));
}
}
public class LinkedList {
private Node first; // 第一个节点
private Node last; // 尾节点
private int size; // 链表长度
public LinkedList() {
}
public void add(Object obj) {
// 向尾部添加一个新的节点
Node newNode = new Node();
newNode.value = obj;
// 判断是否是第一次添加
if (first == null) {
this.first = newNode;
this.last = newNode;
} else {
newNode.prev = last;
last.next = newNode;
last = newNode;
}
this.size++;
}
public void add(int index, Object obj) {
Node newNode = new Node();
newNode.value = obj;
Node oldNode = (Node) this.get(index);
newNode.next = oldNode;
newNode.prev = oldNode.prev;
oldNode.prev.next = newNode;
oldNode.prev = newNode;
}
/*
添加至第一个元素
*/
public void addFirst(Object obj) {
if (this.first == null) {
System.out.println("为空");
this.add(obj);
return;
}
Node newNode = new Node();
newNode.value = obj;
newNode.next = this.first;
this.first.prev = newNode;
this.first = newNode;
}
/*
添加至最后
*/
public void addLast(Object obj) {
if (this.first == null) {
System.out.println("为空");
this.add(obj);
return;
}
Node newNode = new Node();
newNode.value = obj;
this.last.next = newNode;
newNode.prev = this.last;
this.last = newNode;
}
public void clear() {
this.size = 0;
this.first = null;
this.last = null;
System.gc();
}
/*
通过下标获取对应的元素
*/
public Object get(int index) {
if (index >= this.size || index < 0) {
throw new RuntimeException("对不起,不存在这个下标");
}
Node temp = first;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
return temp.value;
}
public Object getFirst() {
if (this.first == null) {
System.out.println("链表为空");
//抛出异常也可
return null;
}
return this.first.value;
}
public Object getLast() {
if (this.first == null) {
System.out.println("链表为空");
//抛出异常也可
return null;
}
return this.last.value;
}
public boolean contains(Object obj) {
if (size == 0) {
System.out.println("空");
return false;
}
Node temp = first;
for (int i = 0; i < size; i++) {
if (temp == obj) {
return true;
}
temp = temp.next;
}
return false;
}
}
ArrayList
List 接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。 每个 ArrayList 实例都有一个容量 。该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长。 此实现不是同步的。
public class ArrayList {
private Object[] objs;
private int size;
private int capacity;
public ArrayList() {
this.capacity = 10;
this.objs = new Object[this.capacity];
}
public ArrayList(int capacity) {
this.capacity = capacity;
this.objs = new Object[this.capacity];
}
public boolean contains(Object obj){
if (size == 0){
System.out.println("空");
return false;
}
for (int i = 0; i < size; i++) {
if (this.objs[i] == obj){
return true;
}
}
return false;
}
public void add(Object obj) {
if (this.isFull()) {
// 扩容
this.grow();
}
this.objs[size++] = obj;
}
private void grow() {
// 1.5 倍
int newCapaCity = this.capacity + (this.capacity >>> 1);
System.out.println("扩容开始,容量由" + this.capacity + "变为:" + newCapaCity);
this.objs = Arrays.copyOf(this.objs, newCapaCity);
this.capacity = newCapaCity;
System.out.println("扩容成功");
}
private boolean isFull() {
return this.size == this.capacity;
}
public void add(int index, Object obj) {
if (this.isFull()) {
this.grow();
}
for (int i = size; i > index; i--) {
this.objs[i] = this.objs[i - 1];
}
this.objs[index] = obj;
this.size++;
}
public void remove(int index) {
for (int i = index; i < this.size - 1; i++) {
this.objs[index] = this.objs[index + 1];
}
this.size--;
}
//移除指定对象
public void remove(Object obj) {
for (int i = 0; i < size; i++) {
if (this.objs[i] == obj){
for (; i < size - 1; i++) {
this.objs[i] = this.objs[i + 1]; // 讲下标i之后的元素全部向前移动移位
}
this.size--;
return;
}
}
System.out.println("找不到指定对象。");
}
/*
根据下标更新对象
*/
public void update(int index, Object obj) {
this.objs[index] = obj;
}
public Object get(int index) {
if (index < size) {
return null;
}
return this.objs[index];
}
public Object[] list() {
return Arrays.copyOf(this.objs, size);
}
public void clear() {
this.capacity = 10;
this.objs = new Object[this.capacity];
}
public String toString() {
return "ObjectMangerImpl [objs=" + Arrays.toString(objs) + ", size=" + size + ", capacity=" + capacity + "]";
}
public int size() {
return this.size;
}
}
public class Demo {
@Test
public void test01(){
ArrayList list = new ArrayList();
list.add("123");
list.add("456");
list.add("789");
list.add("zhanghan");
list.add("qwertyuio");
list.add("hhh");
System.out.println(list);
//判断是否为空
System.out.println(list.isEmpty());
//删除指定元素
System.out.println(list.remove("hhh"));
//删除指定下标对应的元素
System.out.println(list.remove(3));
//数组长度
System.out.println(list.size());
//判断是否存在指定元素
System.out.println(list.contains("hhh"));
//获取指定下标对应的元素
System.out.println(list.get(3));
//获取指定元素对应的下标
System.out.println(list.indexOf("123"));
System.out.println(list);
}
@Test
public void test02(){
List<String> num = new ArrayList<>();
num.add("哦哦哦");
num.add("呜呜呜");
num.add("啦啦啦");
num.add("哈哈哈");
num.add("哒哒哒");
System.out.println(num.get(2));
for (int i = 0; i < num.size(); i++) {
System.out.println(num.get(i));
}
}
}
Vector
Vector 类实现了一个动态数组。和 ArrayList 很相似,但是两者是不同的:
- Vector 是同步访问的。
- Vector 包含了许多传统的方法,这些方法不属于集合框架。
Vector 主要用在事先不知道数组的大小,或者只是需要一个可以改变大小的数组的情况。
Vector 类支持 4 种构造方法:
第一种构造方法创建一个默认的向量,默认大小为 10:
Vector()
第二种构造方法创建指定大小的向量。
Vector(int size)
第三种构造方法创建指定大小的向量,并且增量用 incr 指定。增量表示向量每次增加的元素数目。
Vector(int size,int incr)
第四种构造方法创建一个包含集合 c 元素的向量:
Vector(Collection c)
public class VectorDemo {
public static void main(String args[]) {
// initial size is 3, increment is 2
Vector v = new Vector(3, 2);
System.out.println("Initial size: " + v.size());
System.out.println("Initial capacity: " +
v.capacity());
v.addElement(new Integer(1));
v.addElement(new Integer(2));
v.addElement(new Integer(3));
v.addElement(new Integer(4));
System.out.println("Capacity after four additions: " +
v.capacity());
v.addElement(new Double(5.45));
System.out.println("Current capacity: " +
v.capacity());
v.addElement(new Double(6.08));
v.addElement(new Integer(7));
System.out.println("Current capacity: " +
v.capacity());
v.addElement(new Float(9.4));
v.addElement(new Integer(10));
System.out.println("Current capacity: " +
v.capacity());
v.addElement(new Integer(11));
v.addElement(new Integer(12));
System.out.println("First element: " +
(Integer)v.firstElement());
System.out.println("Last element: " +
(Integer)v.lastElement());
if(v.contains(new Integer(3)))
System.out.println("Vector contains 3.");
// enumerate the elements in the vector.
Enumeration vEnum = v.elements();
System.out.println("\nElements in vector:");
while(vEnum.hasMoreElements())
System.out.print(vEnum.nextElement() + " ");
System.out.println();
}
}
Stack
栈是Vector的一个子类,它实现了一个标准的后进先出的栈。
堆栈只定义了默认构造函数,用来创建一个空栈。 堆栈除了包括由Vector定义的所有方法,也定义了自己的一些方法。
Stack()
import java.util.*;
public class StackDemo {
static void showpush(Stack<Integer> st, int a) {
st.push(new Integer(a));
System.out.println("push(" + a + ")");
System.out.println("stack: " + st);
}
static void showpop(Stack<Integer> st) {
System.out.print("pop -> ");
Integer a = (Integer) st.pop();
System.out.println(a);
System.out.println("stack: " + st);
}
public static void main(String args[]) {
Stack<Integer> st = new Stack<Integer>();
System.out.println("stack: " + st);
showpush(st, 42);
showpush(st, 66);
showpush(st, 99);
showpop(st);
showpop(st);
showpop(st);
try {
showpop(st);
} catch (EmptyStackException e) {
System.out.println("empty stack");
}
}
}
Queue
队列是一种特殊的线性表,它只允许在表的前端进行删除操作,而在表的后端进行插入操作。LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用。
public class Main {
public static void main(String[] args) {
//add()和remove()方法在失败的时候会抛出异常(不推荐)
Queue<String> queue = new LinkedList<String>();
//添加元素
queue.offer("a");
queue.offer("b");
queue.offer("c");
queue.offer("d");
queue.offer("e");
for(String q : queue){
System.out.println(q);
}
System.out.println("===");
System.out.println("poll="+queue.poll()); //返回第一个元素,并在队列中删除
for(String q : queue){
System.out.println(q);
}
System.out.println("===");
System.out.println("element="+queue.element()); //返回第一个元素
for(String q : queue){
System.out.println(q);
}
System.out.println("===");
System.out.println("peek="+queue.peek()); //返回第一个元素
for(String q : queue){
System.out.println(q);
}
}
}