1.實現思路:通過雙鏈表來實現,并且保留該表兩端的引用。
2.實現設計:
a. MyLinkedList類:包含到兩端的鏈,表的大小以及一些方法。
b. Node類:一個節點包含數據以及前一個節點的鏈和下一個節點的鏈,以及其構造方法。
c. LinkedListIterator類:實現接口Iterator,提供next,hasNext,remove方法的實現。
3. 具體實現過程---Coding:
a. 實現Node類:
//定義節點,類型為AnyType
private static class Node<AnyType>{
//通過構造函數,創建一個節點
public Node(AnyType d, Node<AnyType> p, Node<AnyType> n){
data = d;
prev = p;
next = n;
}
//當前結點數據
public AnyType data;
//向前驅點
public Node<AnyType> prev;
//向后驅點
public Node<AnyType> next;
}
b. 定義一些常量:
public class MyLinkedList<Object> implements Iterable<Object> {
//定義當前長度
private int theSize;
//定義操作次數,增加,刪除等影響結構的操作
private int modCount = 0;
//定義開始標記
private Node<Object> beginMarker;
//定義結束標記
private Node<Object> endMarker;
}
c.構造函數以及初始化操作:
//創建時,清空所有之前的數據
public MyLinkedList(){
doClear();
}
//清空操作
public void clear(){
doClear();
}
//實現具體的清空操作
public void doClear() {
//定義開始節點
beginMarker = new Node<Object>(null,null,null);
//定義結束節點,注意這里將開始節點作為結束節點的向前節點
endMarker = new Node<Object>(null, beginMarker, null);
//將結束節點作為開始節點的向后節點
beginMarker.next = endMarker;
//初始化大小為0
theSize = 0;
//操作加1
modCount ++;
}
//返回當前長度
public int size(){
return theSize;
}
//判斷當前鏈表是否為空
public boolean isEmpty(){
return theSize == 0;
}
d. get操作,獲取到節點以及節點數據等
/**
* 根據鏈表位置獲取到對應的數據:通過調用getNode方法獲取到當前結點,
* 再獲取到當前結點的數據
* @param idx 傳入的位置
* @return
*/
public Object get(int idx){
return getNode(idx).data;
}
/**
* 獲取到對應位置的節點:調用具體的getNode方法去獲取
* @param idx
* @return
*/
private Node<Object> getNode(int idx){
return getNode(idx, 0 , size());
}
/**
* 實現根據位置獲取到節點
* @param idx 當前位置
* @param lower 開始位置
* @param upper 結束位置
* @return
*/
private Node<Object> getNode(int idx, int lower, int upper){
//定義一個臨時節點
Node<Object> p;
//若傳入的位置超出范圍,則拋出異常
if (idx < lower || idx > upper)
throw new IndexOutOfBoundsException();
//若當前位置在左邊,則從開始出進行向后遍歷
if (idx < size() / 2){
//移動到開始處
p = beginMarker;
//遍歷直到到達所要求的位置
for (int i = 0; i < idx; i ++){
p = p.next;
}
}
//若當前位置在右邊,則從尾部開始進行向前遍歷
else {
p = endMarker;
for (int i = size(); i > idx; i --){
p = p.prev;
}
}
return p;
}
e. set操作,用于更新節點數據:
/**
* 更新數據操作
* @param idx 傳入的鏈表位置
* @param newVal 更新的數據
* @return
*/
public Object set(int idx, Object newVal){
//獲取到對應位置的節點
Node<Object> p = getNode(idx);
//獲取到當前數據
Object oldVal = p.data;
p.data = newVal;
//返回原來的數據
return oldVal;
}
f. 添加操作:主要理解addBefore操作
/**
* 實現默認方式添加元素
* @param x
* @return
*/
public boolean add(Object x){
//調用add方法,添加到尾部
add(size(), x);
return true;
}
/**
* 實現添加到具體的某個位置中
* @param idx
* @param x
*/
public void add(int idx, Object x) {
addBefore(getNode(idx), x);
}
/**
* 實現具體的添加操作
* @param p 當前位置的節點
* @param x 節點數據
*/
private void addBefore(Node<Object> p , Object x){
//根據p節點創建一個新的節點
Node<Object> newNode = new Node<Object>(x, p.prev, p);
//連接新節點與前后兩個節點
newNode.prev.next = newNode;
p.prev = newNode;
//長度和操作次數++
theSize ++;
modCount ++;
}
添加操作示意圖:
add_node
//實際上,通過構造函數,便完成了示意圖中的1和2操作
Node<Object> newNode = new Node<Object>(x, p.prev, p);
//實現了操作3
newNode.prev.next = newNode;
//實現了操作4
p.prev = newNode;
g. 實現刪除節點操作:
/**
* 實現移除某個位置的節點
* @param idx
* @return
*/
public Object remove(int idx){
return remove(getNode(idx));
}
/**
* 具體移除節點操作
* @param p 傳入要移除的節點
* @return
*/
private Object remove(Node<Object> p){
//移除當前節點
p.next.prev = p.prev;
p.prev.next = p.next;
//長度--
theSize --;
//操作次數++
modCount ++;
//返回移除節點的數據
return p.data;
}
刪除示意圖:
delete_node.png
h. 實現查找元素位置操作:
/**
* 實現查找鏈表中首先出現的元素位置
* @param x
* @return
*/
public int indexOf(Object x){
int index = 0;
//若傳入的數據為空
if (x == null){
//遍歷鏈表,查找是否含有數據為null的節點,找到后立即返回當前位置
for (Node<Object> node = beginMarker.next; node != endMarker; node = node.next){
if (node.data == null){
return index;
}
index ++;
}
}
//數據不為空時,使用equals方法進行比較
else {
for (Node<Object> node = beginMarker.next; node != endMarker; node = node.next){
if (x.equals(node.data)){
return index;
}
index ++;
}
}
return -1;
}
/**
* 實現查找鏈表中元素最后出現的位置
* 從尾節點開始向前遍歷搜查
* @param x
* @return
*/
public int lastIndexOf(Object x){
int index = size() - 1;
if (x == null){
for (Node<Object> node = endMarker.prev; node != beginMarker; node = node.prev){
if (node.data == null){
return index;
}
index --;
}
} else {
for (Node<Object> node = endMarker.prev; node != beginMarker; node = node.prev){
if (x.equals(node.data)){
return index;
}
index --;
}
}
return -1;
}
i. 實現LinkedListIterator類:
private class LinkedListIterator implements Iterator<Object>{
//定義當前結點為始節點的下一個節點
private Node<Object> current = beginMarker.next;
//定義操作次數
private int expectedModCount = modCount;
//判斷是否可以進行刪除
private boolean okToRemove = false;
//判斷是否存在下一個節點
@Override
public boolean hasNext() {
return current != endMarker;
}
//獲取到下一個節點數據
@Override
public Object next() {
//操作次數不一致拋出異常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
//不存在下一個節點,拋出異常
if (!hasNext())
throw new NoSuchElementException();
//獲取到下一個節點的數據,并設置okToRemove為true,表示可以進行刪除
Object nextItem = current.data;
current = current.next;
okToRemove = true;
return nextItem;
}
//進行刪除操作
public void remove(){
//操作次數不一致,拋出異常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
//無法進行刪除操作,必須先進行next,才可以進行remove操作
if (!okToRemove)
throw new IllegalStateException();
//調用鏈表中的remove方法進行刪除操作,注意傳入的是current.pre節點
MyLinkedList.this.remove(current.prev);
//操作次數++
expectedModCount ++;
okToRemove = false;
}
}
完整代碼如下:
/**
* Created by Administrator on 2017/3/5/005.
* 實現自定義LinkedList
*/
public class MyLinkedList<Object> implements Iterable<Object> {
//定義當前長度
private int theSize;
//定義操作次數,增加,刪除等影響結構的操作
private int modCount = 0;
//定義開始標記
private Node<Object> beginMarker;
//定義結束標記
private Node<Object> endMarker;
//定義節點,類型為AnyType
private static class Node<AnyType>{
//通過構造函數,創建一個節點
public Node(AnyType d, Node<AnyType> p, Node<AnyType> n){
data = d;
prev = p;
next = n;
}
//當前結點數據
public AnyType data;
//向前驅點
public Node<AnyType> prev;
//向后驅點
public Node<AnyType> next;
}
//創建時,清空所有之前的數據
public MyLinkedList(){
doClear();
}
//清空操作
public void clear(){
doClear();
}
//實現具體的清空操作
public void doClear() {
//定義開始節點
beginMarker = new Node<Object>(null,null,null);
//定義結束節點,注意這里將開始節點作為結束節點的向前節點
endMarker = new Node<Object>(null, beginMarker, null);
//將結束節點作為開始節點的向后節點
beginMarker.next = endMarker;
//初始化大小為0
theSize = 0;
//操作加1
modCount ++;
}
//返回當前長度
public int size(){
return theSize;
}
//判斷當前鏈表是否為空
public boolean isEmpty(){
return theSize == 0;
}
/**
* 根據鏈表位置獲取到對應的數據:通過調用getNode方法獲取到當前結點,
* 再獲取到當前結點的數據
* @param idx 傳入的位置
* @return
*/
public Object get(int idx){
return getNode(idx).data;
}
/**
* 更新數據操作
* @param idx 傳入的鏈表位置
* @param newVal 更新的數據
* @return
*/
public Object set(int idx, Object newVal){
//獲取到對應位置的節點
Node<Object> p = getNode(idx);
//獲取到當前數據
Object oldVal = p.data;
p.data = newVal;
//返回原來的數據
return oldVal;
}
/**
* 獲取到對應位置的節點:調用具體的getNode方法去獲取
* @param idx
* @return
*/
private Node<Object> getNode(int idx){
return getNode(idx, 0 , size());
}
/**
* 實現根據位置獲取到節點
* @param idx 當前位置
* @param lower 開始位置
* @param upper 結束位置
* @return
*/
private Node<Object> getNode(int idx, int lower, int upper){
//定義一個臨時節點
Node<Object> p;
//若傳入的位置超出范圍,則拋出異常
if (idx < lower || idx > upper)
throw new IndexOutOfBoundsException();
//若當前位置在左邊,則從開始出進行向后遍歷
if (idx < size() / 2){
//移動到開始處
p = beginMarker;
//遍歷直到到達所要求的位置
for (int i = 0; i < idx; i ++){
p = p.next;
}
}
//若當前位置在右邊,則從尾部開始進行向前遍歷
else {
p = endMarker;
for (int i = size(); i > idx; i --){
p = p.prev;
}
}
return p;
}
/**
* 實現默認方式添加元素
* @param x
* @return
*/
public boolean add(Object x){
//調用add方法,添加到尾部
add(size(), x);
return true;
}
/**
* 實現添加到具體的某個位置中
* @param idx
* @param x
*/
public void add(int idx, Object x) {
addBefore(getNode(idx), x);
}
/**
* 實現具體的添加操作
* @param p 當前位置的節點
* @param x 節點數據
*/
private void addBefore(Node<Object> p , Object x){
//實際上,通過構造函數,便完成了示意圖中的1和2操作
Node<Object> newNode = new Node<Object>(x, p.prev, p);
//實現了操作3
newNode.prev.next = newNode;
//實現了操作4
p.prev = newNode;
//長度和操作次數++
theSize ++;
modCount ++;
}
/**
* 實現移除某個位置的節點
* @param idx
* @return
*/
public Object remove(int idx){
return remove(getNode(idx));
}
/**
* 具體移除節點操作
* @param p 傳入要移除的節點
* @return
*/
private Object remove(Node<Object> p){
//移除當前節點
p.next.prev = p.prev;
p.prev.next = p.next;
//長度--
theSize --;
//操作次數++
modCount ++;
//返回移除節點的數據
return p.data;
}
/**
* 獲取到第一個節點數據
* @return
*/
public Object getFirst(){
//先判斷鏈表是否為空,為空則拋出異常
if (isEmpty()){
throw new NoSuchElementException();
}
return beginMarker.next.data;
}
//獲取到鏈表中的最后一個節點數據
public Object getLast(){
if (isEmpty()){
throw new NoSuchElementException();
}
return endMarker.prev.data;
}
//移除鏈表中第一個節點
public Object removeFirst(){
if (isEmpty()){
throw new NoSuchElementException();
}
//調用remove方法,移除開始節點的下一個節點即可
return remove(beginMarker.next);
}
//移除鏈表中的最后一個節點
public Object removeLast(){
if (isEmpty()){
throw new NoSuchElementException();
}
//調用remove方法,移除結束節點的上一個節點即可
return remove(endMarker.prev);
}
//從頭部開始添加節點
public void addFirst(Object x){
//將添加節點設置為頭節點即可
addBefore(beginMarker.next, x);
}
//從尾部添加節點
public void addLast(Object x){
add(x);
}
//添加一個Collection集合
public void addAll(Collection<Object> collection){
//添加集合為空,則拋出異常
if (collection == null){
throw new NullPointerException();
}
//遍歷集合,并逐個添加到鏈表中
for (Object aCollection : collection) {
add(aCollection);
}
}
//判斷鏈表中是否含有某個元素,調用indexOf方法即可
public boolean contains(Object x){
return indexOf(x) != -1;
}
/**
* 實現查找鏈表中首先出現的元素位置
* @param x
* @return
*/
public int indexOf(Object x){
int index = 0;
//若傳入的數據為空
if (x == null){
//遍歷鏈表,查找是否含有數據為null的節點,找到后立即返回當前位置
for (Node<Object> node = beginMarker.next; node != endMarker; node = node.next){
if (node.data == null){
return index;
}
index ++;
}
}
//數據不為空時,使用equals方法進行比較
else {
for (Node<Object> node = beginMarker.next; node != endMarker; node = node.next){
if (x.equals(node.data)){
return index;
}
index ++;
}
}
return -1;
}
/**
* 實現查找鏈表中元素最后出現的位置
* 從尾節點開始向前遍歷搜查
* @param x
* @return
*/
public int lastIndexOf(Object x){
int index = size() - 1;
if (x == null){
for (Node<Object> node = endMarker.prev; node != beginMarker; node = node.prev){
if (node.data == null){
return index;
}
index --;
}
} else {
for (Node<Object> node = endMarker.prev; node != beginMarker; node = node.prev){
if (x.equals(node.data)){
return index;
}
index --;
}
}
return -1;
}
/**
* 實現鏈表的遍歷
* @return
*/
public Iterator<Object> iterator(){
return new LinkedListIterator();
}
private class LinkedListIterator implements Iterator<Object>{
//定義當前結點為始節點的下一個節點
private Node<Object> current = beginMarker.next;
//定義操作次數
private int expectedModCount = modCount;
//判斷是否可以進行刪除
private boolean okToRemove = false;
//判斷是否存在下一個節點
@Override
public boolean hasNext() {
return current != endMarker;
}
//獲取到下一個節點數據
@Override
public Object next() {
//操作次數不一致拋出異常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
//不存在下一個節點,拋出異常
if (!hasNext())
throw new NoSuchElementException();
//獲取到下一個節點的數據,并設置okToRemove為true,表示可以進行刪除
Object nextItem = current.data;
current = current.next;
okToRemove = true;
return nextItem;
}
//進行刪除操作
public void remove(){
//操作次數不一致,拋出異常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
//無法進行刪除操作,必須先進行next,才可以進行remove操作
if (!okToRemove)
throw new IllegalStateException();
//調用鏈表中的remove方法進行刪除操作,注意傳入的是current.pre節點
MyLinkedList.this.remove(current.prev);
//操作次數++
expectedModCount ++;
okToRemove = false;
}
}
}
測試代碼:
public class LinkedListTest {
public static void main(String[] args){
//進行添加操作
MyLinkedList<String> myLinkedList = new MyLinkedList<>();
myLinkedList.add("Java");
myLinkedList.add("C++");
myLinkedList.add("Python");
myLinkedList.add(2, "PHP");
//遍歷結果
printLinkedList(myLinkedList.iterator());
//進行刪除和更新操作
myLinkedList.remove(2);
myLinkedList.set(1,"JavaScript");
printLinkedList(myLinkedList.iterator());
//獲取到首尾元素
System.out.println("first data : " + myLinkedList.getFirst());
System.out.println("last data : " + myLinkedList.getLast());
//移除首尾節點
myLinkedList.removeFirst();
myLinkedList.removeLast();
printLinkedList(myLinkedList.iterator());
//分別從首尾部添加
myLinkedList.addFirst("C#");
myLinkedList.addLast("CSS");
printLinkedList(myLinkedList.iterator());
//清空操作
myLinkedList.clear();
printLinkedList(myLinkedList.iterator());
//addAll方法
List<String> list = new ArrayList<>();
list.add("JAVA");
list.add("C++");
list.add("C");
list.add("JavaScript");
list.add("C");
list.add("HTML");
myLinkedList.addAll(list);
printLinkedList(myLinkedList.iterator());
//查找元素
System.out.println("是否存在CSS教程: " + myLinkedList.contains("CSS"));
System.out.println("是否存在HTML教程: " + myLinkedList.contains("HTML"));
System.out.println("C教程開始的位置為: " + myLinkedList.indexOf("C"));
System.out.println("C教程最后的位置為: " + myLinkedList.lastIndexOf("C"));
}
private static void printLinkedList(Iterator<String> iterator){
System.out.print("當前鏈表為: ");
while (iterator.hasNext()){
System.out.print(iterator.next() + " ");
}
System.out.println();
}
}
輸出結果:
當前鏈表為: Java C++ PHP Python
當前鏈表為: Java JavaScript Python
first data : Java
last data : Python
當前鏈表為: JavaScript
當前鏈表為: C# JavaScript CSS
當前鏈表為:
當前鏈表為: JAVA C++ C JavaScript C HTML
是否存在CSS教程: false
是否存在HTML教程: true
C教程開始的位置為: 2
C教程最后的位置為: 4