1. 程式人生 > >使用迭代器(Iterator)來實現連結串列的相關操作

使用迭代器(Iterator)來實現連結串列的相關操作

在這一篇裡,要講的是如何使用迭代器對連結串列進行相關的操作,比如刪除,獲取,插入等操作,那首先介紹一下什麼是迭代器,java裡面的迭代器的實用性很大,在我們實際對連結串列進行刪除操作時,如果是要對某個限制條件下的所有連結串列資料都刪除,如果是用普通的指標,那就必須每次都對連結串列進行遍歷查詢,符合了條件進行刪除,而效率很低,而不像陣列,有固定的下標位,所以我們設法給予一個類似陣列下標的東西來表明連結串列的位置。

這時我們使用了一種類,叫迭代器類,迭代器類包含對資料結構的資料項的引用,並用來遍歷這些結構的物件。

好了,大概介紹了一下,我們來看看迭代器的具體使用吧:

這裡筆者用迭代器去代替一些連結串列操作,也就是這些操作可以在連結串列裡執行的,但是放在迭代器裡能更加明白其用法,首先建立一個連結串列:

<span style="font-size:18px;">public class Link {
	private long dData;
	private Link next;
	
	public Link(long dd){
		dData = dd;
	}
	
	public void displayLink(){
		System.out.print(dData + "  ");
	}
}</span>
這裡有long型的資料,也有next的引用,作為標識下個鏈節點的引用,然後我們來建立連結串列:
<span style="font-size:18px;">public class LinkList {

	private Link first;
	
	public LinkList(){
		first = null;                         //建構函式初始化首節點
	}
	
	public Link getFirst() {                 //獲取第一個節點
		return first;
	}

	public void setFirst(Link first) {        //設定第一個節點
		this.first = first;
	}
	
	public boolean isEmpty(){                //判斷連結串列是否為空
		return (first == null);
	}
	
	public LinkIterator myIterator(){        //定義迭代器,與之聯絡起來
		return new LinkIterator(this);
	}
	
	public void displayLinklist(){          //打印出連結串列中的元素
		Link current = first;
		while (current != null) {
			System.out.print(current.dData + "   ");
			current = current.next;
		}
		System.out.println("");
	}
}</span>

其他函式沒什麼好說的,主要要注意一下關於連結串列和迭代器之間的聯絡,在連結串列中建立迭代器時,傳遞給迭代器一個引用,這個引用儲存在迭代器的一個欄位中,這樣迭代器就可以訪問連結串列中的私有資料欄位了。

然後是迭代器類的實現:

public class LinkIterator {
	private Link current;
	private Link previous;
	private LinkList outlist;
	
	public LinkIterator(LinkList mLinkList){                  //建構函式,同時進行將迭代器置於表頭
		outlist = mLinkList;
		reset();
	}
	
	public void reset(){									//將迭代器置於表頭方法
		current = outlist.getFirst();
		previous = null;
	}
	
	public boolean atEnd(){                              //判斷迭代器是否位置在表尾
		return (current.next == null);
	}
	
	public void nextLink(){                             //將迭代器的位置向後移動一位
		previous = current;
		current = current.next;
	}
	
	public Link getCurrent(){                           //返回此時迭代器所指鏈節點的值
		return current;
	}
	
	public void inserAfter(long dd){                   //插入迭代器所指鏈節點的後面
		Link newLink = new Link(dd);
		if (outlist.isEmpty()) {
			outlist.setFirst(newLink);
			current = newLink;
		}
		else {
			newLink.next = current.next;
			current.next = newLink;
			nextLink();
		}
	}
	
	public void insertBefore(long dd){                   //插入迭代器所指鏈節點對的前面
		Link newlink = new Link(dd);
		
		if (previous == null) {
			newlink.next = outlist.getFirst();
			outlist.setFirst(newlink);
			reset();
		}else {
			newlink.next = previous.next;
			previous.next = newlink;
			current = newlink;
		}
	}
	
	public long deleteLink(){                            //刪除迭代器所指的鏈節點
		long data = current.dData;
		
		if (previous == null) {
			outlist.setFirst(current.next);
			reset();
		}else {
			previous.next = current.next;
			if (atEnd()) {
				reset();
			}else {
				current = current.next;
			}
		}
		return data;
	}
}
這個迭代器類實現要注意節點直接的關係,注意判斷節點的位置和表是否為空,這兩點經常會忘記。然後就是主要函式的呼叫了,這裡筆者分為幾個操作進行功能的呼叫:
public class IteratorTest {
	
	public static void main(String[] args) throws IOException {
		LinkList mLinkList = new LinkList();
		LinkIterator mIterator = mLinkList.myIterator();
		
		long value;
		
		mIterator.inserAfter(20);
		mIterator.inserAfter(40);
		mIterator.inserAfter(80);
		mIterator.insertBefore(60);
		
		while (true) {
			System.out.println("please input the letter to operate the Iterator: ");
			System.out.println("you can input the word of s,r,g,n,b,a,d: ");
			System.out.flush();
			int m = getChar();
			
			switch (m) {
			case 's':
				if (!mLinkList.isEmpty()) {
					mLinkList.displayLinklist();
				}else {
					System.out.println("the linklist is empty");
				}
				break;
				
			case 'r':
				mIterator.reset();
				break;
				
			case 'g':
				if (!mLinkList.isEmpty()) {
					value = mIterator.getCurrent().dData;
					System.out.println("Return data is : " + value);
				}else {
					System.out.println("the linklist is empty");
				}
				break;
				
			case 'n':
				if (!mLinkList.isEmpty() && !mIterator.atEnd()) {
					mIterator.nextLink();
				}else {
					System.out.println("something happening");
				}
				break;
			
			case 'b':
				if (!mLinkList.isEmpty()) {
					System.out.print("input the word you want to insert ");
					System.out.flush();
					value = getInt();
					mIterator.insertBefore(value);
				}else {
					System.out.println("something happening");
				}
				break;
			
			case 'a':
				if (!mLinkList.isEmpty()) {
					System.out.print("input the word you want to insert ");
					System.out.flush();
					value = getInt();
					mIterator.inserAfter(value);
				}else {
					System.out.println("something happening");
				}
				break;
				
			case 'd':
				if (!mLinkList.isEmpty()) {
					value = mIterator.deleteLink();
					System.out.print("the deleted data is : " + value);
				}else {
					System.out.println("something happening");
				}
				break;
			default:
				System.out.println("Invalid entry");
				break;
			}
		}//end while
	}//end main
	
	public static String getString() throws IOException{
		InputStreamReader inReader = new InputStreamReader(System.in);
		BufferedReader buf = new BufferedReader(inReader);
		String mString = buf.readLine();
		return mString;
	}
	
	public static char getChar() throws IOException{
		char a;
		a = getString().charAt(0);
		return a;
	}
	
	public static int getInt() throws IOException{
		int a ;
		String s = getString();
		a = Integer.parseInt(s);
		return a;
	}
}

主函式的呼叫要注意對錶是否為空的判斷,以及對迭代器位置的判斷,如果為空或者在尾部,應該做出相應的處理,這裡更好應該在方法中就進行自動的判斷,筆者在這裡實現的是單鏈表,大家可以去嘗試實現以下雙向連結串列是如何實現的。

下面是執行結果:


好了,迭代器就講到這裡,大家有疑問可以評論。