[Java]ArrayList与LinkedList的模拟实现

来源:互联网 发布:linux修改用户组 编辑:程序博客网 时间:2024/06/05 10:40

    Java中的List继承自Collection接口。List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。跟Set集合不同的是,List允许有重复元素。对于满足e1.equals(e2)条件的e1与e2对象元素,可以同时存在于List集合中。当然,也有List的实现类不允许重复元素的存在。除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。

    实现List接口的常用类有LinkedList,ArrayList,这里模拟两种List的特点进行实现从而加深理解。


一、双向链表LinkedSequence:


a) 私有成员变量:

private Entry head;private int cnt;

i. head为Entry型的每个LinkedSequence头指针,通过它能够访问该对象的所有内部数据,注意head不存储数据,只是用作头节点标记。
Entry结构具体在下面介绍。
ii. cnt记录每个LinkedSequence内部的成员个数,为了方便内部类的使用,创建了私有方法setSize()对齐进行修改。


b) 私有内部静态类:

private static class Entry {SequenceItem si;Entry befo;Entry next;Entry(SequenceItem si, Entry befo, Entry next) {this.si = si;this.befo = befo;this.next = next;}}

每个实体含有一个SequenceItem型的私有成员变量si,指向前一个Entry的引用befo,指向下一个Entry的引用next。
c) 构造函数:
LinkedSequence() {head = new Entry(null, null, null);head.next = head;head.befo = head;cnt = 0;}

i. 将head初始化,所有数据成员均为空;
ii. 将head的next和befo均标记为自己;
iii. cnt计数清零。


d) 公有方法:

i. public void add(SequenceItem item)链表尾段添加item元素:
创建一个Entry型的tmp,它的si为item,befo即head的befo(head的befo指向链表中的最后一个Entry),next即head。
将原来的末端元素的next标记为tmp,将head的befo指向新的末端元素tmp。
计数器cnt加一。

ii. public SequenceItem get(int i)获取链表中第i个元素,起始下标为0:
如果索引i超出[0, cnt),则抛出越界异常。
创建Entry e指向第一个元素,通过next向后迭代i次,返回此时的e.si。

iii. public void remove(SequenceItem item)删除链表中的第一个item元素:
如果item为空,不做处理;
创建Entry e指向第一个元素,根据e扫描链表,如果有一个e的si与item相等,创建一个Entry tmp指向此时的e,将e的前驱节点的next标记为e的后继节点,将e的后继节点的befo标记为e的前驱结点。
将tmp的befo、next和si均标记为空,计数器cnt减一。
如果遍历整个列表结束后没有找到,则抛出NoSuchElementException异常。

iv. public boolean contains(SequenceItem item)判断链表中是否含有item元素:
与remove()操作类似,只不过返回true和false不做敖述。

v. public int size()返回链表的长度:返回cnt。

vi. public boolean isEmpty()判断链表是否为空:
返回cnt==0?

vii. public SequenceItem[] toArray()将链表转化为数组:
创建一个大小为cnt的SequenceItem数组ans,依次将链表中每个节点e的si放入ans即可。

viii. public boolean equals(Sequence seq)判断两个链表元素是否相对:
如果两个Sequence的大小不等,则不再进行比较,直接返回false。
否则依次比较两个sequence的全部元素,一旦含有一个不同则返回false。

ix. public String toString()将链表转化为字符串:
与toArray类似,只不过将原来的ans用string存储,并在放入结束后返回Arrays.toString(ans)。

x. public SeqIterator iterator()正向迭代器:
返回一个SeqIterator的内部匿名类对象,含有私有成员变量index,记录当前访问元素的相对位置,初始化为0;Entry e记录当前将要访问的节点,初始化为链表的第一个元素。
public boolean hasNext():返回index是否小于LinkedSequence.this.size()。
public SequenceItem next():返回当前e.si,index加1,e指向e.next。
public void remove():只有当index大于0时,才可以将前一个元素删除,删除操作同remove()。注意删除后需要将index减一!

xi. public SeqIterator reverseIterator()反向迭代器:
返回一个SeqIterator的内部匿名类对象,含有私有成员变量index,记录当前访问元素的相对位置,初始化为size()-1;Entry e记录当前将要访问的节点,初始化为链表的最后一个元素。
public boolean hasNext():返回index是否大于-1。
public SequenceItem next():返回当前e.si,index减1,e指向e.befo。
public void remove():只有当index小于size()-1时,才可以将后一个元素删除,删除操作同remove()。注意此时无需修改index。

xii. public BiSeqIterator biIterator()双向迭代器:
即前两种迭代器的综合。


二、 变长数组ArraySequence:

a) 私有成员变量:

private SequenceItem[] sequenceItemArray = new SequenceItem[2];private int cnt = 0;

i. sequenceItemArray为每个ArraySequence数据存储数组。
ii. cnt记录每个ArraySequence内部的成员个数,与数组大小不同。

b) 构造函数:

ArraySequence() {sequenceItemArray = new SequenceItem[2];cnt = 0;}

i. 将sequenceItemArray初始化大小为2;
ii. cnt计数清零。

c) 公有方法:基本与LinkedSequence类似,主要区别在于add()和remove()操作。
i. public void add(SequenceItem item)数组中添加item元素:
首先确保sequenceItemArray的大小可以装下cnt+1个元素,如果超出sequenceItemArray的大小,需要将当前数组大小扩充为原来的一倍,再将item放入,计数器cnt加一。

ii. public void remove(SequenceItem item)删除链表中的第一个item元素:
首先在sequenceItemArray中寻找item的下标,记为i,则后面的cnt-i-1个元素都需要前移,之后将cnt-1下标处置为空。
以上完成了删除操作,需要对容器的大小重新确定,如果当前cnt不足sequenceItemArray长度的1/4,则可将sequenceItemArray的长度缩短一半,方法类似于扩张的方法。

三、 性能比较:

四、源码:

Sequence接口:

import java.util.*;interface Sequence {void add(SequenceItem item);SequenceItem get(int i);void remove(SequenceItem item);boolean contains(SequenceItem item);int size();boolean isEmpty();SeqIterator iterator();SeqIterator reverseIterator();BiSeqIterator biIterator();SequenceItem[] toArray();boolean equals(Sequence seq);String toString();}

SeqIterator接口:

interface SeqIterator {boolean hasNext();SequenceItem next();void remove();}

数据成员SequenceItem类:

public class SequenceItem {private String data;public String getData() {return data;}public void setData(String s) {data = new String(s);}public boolean equals(SequenceItem si) {return this.getData().equals(si.getData());}}

双向链表LinkedSequence:

import java.util.*;public class LinkedSequence implements Sequence {private Entry head;private int cnt;private static class Entry {SequenceItem si;Entry befo;Entry next;Entry(SequenceItem si, Entry befo, Entry next) {this.si = si;this.befo = befo;this.next = next;}}LinkedSequence() {head = new Entry(null, null, null);head.next = head;head.befo = head;cnt = 0;}public void add(SequenceItem item) {Entry tmp = new Entry(item, head.befo, head);tmp.befo.next = tmp;head.befo = tmp;cnt++;}public SequenceItem get(int i) {if (i >= cnt || i < 0) {throw new IndexOutOfBoundsException();}Entry e = head.next;for (int j = 0; j < i; j++) {e = e.next;}return e.si;}public void remove(SequenceItem item) {if (item == null) {return;}Entry e = head.next;for (int i = 0; i < cnt; i++) {if (item.equals(e.si)) {Entry tmp = e;tmp.befo.next = tmp.next;tmp.next.befo = tmp.befo;tmp.befo = null;tmp.next = null;tmp.si = null;cnt--;return;}e = e.next;}throw new NoSuchElementException();}public boolean contains(SequenceItem item) {if (item == null) {return false;}Entry e = head.next;for (int i = 0; i < cnt; i++) {if (item.equals(e.si)) {return true;}e = e.next;}return false;}public int size() {return this.cnt;}private void setSize(int cnt) { // use for inner class to modify cntthis.cnt = cnt;// System.out.println("cnt:"+this.cnt);}public boolean isEmpty() {return this.cnt==0 ? true:false;}public SeqIterator iterator() {return new SeqIterator() {private int index = 0;private Entry e = head.next;public boolean hasNext() {return index<LinkedSequence.this.size();}public SequenceItem next() {SequenceItem res = e.si;e = e.next;index++;return res;}public void remove() {if (index > 0) {Entry tmp = e.befo;tmp.befo.next = tmp.next;tmp.next.befo = tmp.befo;tmp.befo = null;tmp.next = null;tmp.si = null;index--;LinkedSequence.this.setSize(LinkedSequence.this.size()-1);}}};}public SeqIterator reverseIterator() {return new SeqIterator() {private int index = LinkedSequence.this.size()-1;private Entry e = head.befo;public boolean hasNext() {return index>-1;}public SequenceItem next() {SequenceItem res = e.si;e = e.befo;index--;return res;}public void remove() {if (index < LinkedSequence.this.size()-1) {Entry tmp = e.next;tmp.befo.next = tmp.next;tmp.next.befo = tmp.befo;tmp.befo = null;tmp.next = null;tmp.si = null;LinkedSequence.this.setSize(LinkedSequence.this.size()-1);}}};}public BiSeqIterator biIterator() {return new BiSeqIterator() {private int index = 0;private Entry e = head.next;public boolean hasNext() {return index<LinkedSequence.this.size();}public SequenceItem next() {SequenceItem res = e.si;e = e.next;index++;return res;}public void remove() {if (index > 0) {Entry tmp = e.befo;tmp.befo.next = tmp.next;tmp.next.befo = tmp.befo;tmp.befo = null;tmp.next = null;tmp.si = null;index--;LinkedSequence.this.setSize(LinkedSequence.this.size()-1);}}public boolean hasPrevious() {// System.out.println(index);return index>-1;}public SequenceItem previous() {SequenceItem res = e.si;e = e.befo;index--;return res;}};}public SequenceItem[] toArray() {SequenceItem[] ans = new SequenceItem[cnt];Entry e = head.next;for (int i = 0; i < cnt; i++) {ans[i] = e.si;e = e.next;}return ans;}public boolean equals(Sequence seq) { //?if (this.size() != seq.size()) {return false;}Entry e1 = this.head.next;for (int i = 0; i < cnt; i++) {if (!e1.si.equals(seq.get(i))) {return false;}e1 = e1.next;}return true;}public String toString() {String[] s = new String[cnt];Entry e = head.next;for (int i = 0; i < cnt; i++) {s[i] = e.si.getData();e = e.next;}return Arrays.toString(s);}}

变长数组ArraySequence:

import java.util.*;public class ArraySequence implements Sequence {private SequenceItem[] sequenceItemArray;private int cnt;ArraySequence() {sequenceItemArray = new SequenceItem[2];cnt = 0;}private void ensureCapacity(int currCapacity) {if (currCapacity >= sequenceItemArray.length) {int newCapacity = sequenceItemArray.length<<1;sequenceItemArray = Arrays.copyOf(sequenceItemArray, newCapacity);}else if (currCapacity < sequenceItemArray.length/4) {int newCapacity = sequenceItemArray.length>>1;sequenceItemArray = Arrays.copyOf(sequenceItemArray, newCapacity);}}public void add(SequenceItem item) {ensureCapacity(cnt+1);sequenceItemArray[cnt++] = item;}public SequenceItem get(int i) {return sequenceItemArray[i];}public void remove(SequenceItem item) {if (item != null) {for (int i = 0; i < cnt; i++) {if (item.equals(sequenceItemArray[i])) {int numMoved = cnt-i-1;if (numMoved > 0) {System.arraycopy(sequenceItemArray, i+1, sequenceItemArray, i, numMoved);}sequenceItemArray[--cnt] = null;ensureCapacity(cnt);return;}}}}public boolean contains(SequenceItem item) {for (int i = 0; i < cnt; i++) {if (item.equals(sequenceItemArray[i])) {return true;}}return false;}public int size() {// System.out.println(cnt+","+sequenceItemArray.length);return cnt;}public boolean isEmpty() {return cnt==0 ? true:false;}public SeqIterator iterator() {return new SeqIterator() {private int index = 0;public boolean hasNext() {return index<cnt;}public SequenceItem next() {return sequenceItemArray[index++];}public void remove() {if (index > 0) {ArraySequence.this.remove(ArraySequence.this.get(--index));}}};}public SeqIterator reverseIterator() {return new SeqIterator() {private int index = ArraySequence.this.size()-1;public boolean hasNext() {return index>-1;}public SequenceItem next() {return ArraySequence.this.get(index--);}public void remove() {ArraySequence.this.remove(ArraySequence.this.get(index+1));if (index >= ArraySequence.this.size()) {index = ArraySequence.this.size()-1;}}};}public BiSeqIterator biIterator() {return new BiSeqIterator() {private int index = 0;public boolean hasNext() {return index<ArraySequence.this.size();}public SequenceItem next() {return ArraySequence.this.get(index++);}public void remove() {if (index > 0) {ArraySequence.this.remove(ArraySequence.this.get(--index));}}public boolean hasPrevious() {return index>0;}public SequenceItem previous() {return ArraySequence.this.get(--index);}};}public SequenceItem[] toArray() {return sequenceItemArray;}public boolean equals(Sequence seq) {if (this.size() !=seq.size()) {return false;}for (int i = 0; i < this.size(); i++) {if (!this.get(i).equals(seq.get(i))) {return false;}}return true;}public String toString() {String[] s = new String[cnt];for (int i = 0; i < cnt; i++) {s[i] = sequenceItemArray[i].getData();}return Arrays.toString(s);}}

附测试程序test.java:

import java.util.*;public class test {public static void main(String[] args) {// Sequence test = new LinkedSequence();Sequence test = new ArraySequence();SequenceItem tmp = new SequenceItem();// Test add(), size()for (int cnt = 1000; cnt <= 1000000; cnt *= 10) {int testTime = 10;double ans = 0;double[] res = new double[testTime];while (testTime > 0) {// Date begin = new Date();for (int i = 0; i < cnt; i++) {tmp.setData(String.valueOf(i));test.add(tmp);// System.out.println(test.size());}// Date end = new Date();// Date begin = new Date();// for (int i = 0; i < cnt; i++) {// tmp = test.get(0);// // System.out.println(tmp.getData());// test.remove(tmp);// }// Date end = new Date();// Date begin = new Date();// for (int i = 0; i < cnt; i++) {// tmp = test.get(i);// // System.out.println(tmp.getData());// }// Date end = new Date();SeqIterator si = test.iterator();Date begin = new Date();while (si.hasNext()) {si.next();}Date end = new Date();res[--testTime] = ((double)end.getTime()-begin.getTime())/1000;ans += res[testTime];}System.out.println(Arrays.toString(res));System.out.println(ans);}// Test add(), get()// for (int i = 0; i < 10; i++) {// SequenceItem tmp = new SequenceItem();// tmp.setData(String.valueOf(i));// test.add(tmp);// System.out.println(test.get(i).getData());// }// Test iterator(), reverseIterator()// SeqIterator si = test.iterator();// while (si.hasNext()) {// System.out.println(si.next().getData());// si.remove();// }// System.out.println(test.isEmpty());// si = test.reverseIterator();// while (si.hasNext()) {// System.out.println(si.next().getData());// si.remove();// }// System.out.println(test.isEmpty());// Test biIterator()// BiSeqIterator bsi = test.biIterator();// while (bsi.hasNext()) {// System.out.println("test next:");// System.out.println(bsi.next().getData());// // bsi.remove();// }// System.out.println(test.isEmpty());// bsi.previous();// while (bsi.hasPrevious()) {// System.out.println("test previous:");// System.out.println(bsi.previous().getData());// }// System.out.println(test.isEmpty());// Test toString()// System.out.println(test);// Test isEmpty(), get(), remove(), contains(), size()// while (!test.isEmpty()) {// SequenceItem tmp = test.get(0);// System.out.println(tmp.getData());// test.remove(tmp);// System.out.println(test.size());// System.out.println(test.contains(tmp));// }}}




0 0
原创粉丝点击