1. 程式人生 > >資料結構單鏈表的定義(Java)

資料結構單鏈表的定義(Java)

定義一個介面

public interface ILinarList<E> {
    public abstract boolean add(E item);          //新增元素
    public abstract boolean add(int i,E item);    //插入元素
    public abstract E remove(int i);              //刪除元素
    public abstract int indexOf(E item);          //定位元素
    public abstract E get(int i);                 //取表元素 
public abstract int size(); //求線性表長度 public abstract void clear(); //清空線性表 public abstract boolean isEmpty(); //判斷線性表是否為空 }

定義一個結點類

/*
 * 單鏈表的的原理就在結點這裡,在每一個結點中都包含一個下一個結點的地址,
 * 如果想要訪問下一個結點,就要通過上一個結點來呼叫他的成員變數next,以此類推
 */
public class Node<E> {
    E item;//建立一個泛型類item
Node<E> next;//建立一個結點類型別 public Node(E element,Node <E> next) { this.item=element; this.next=next; } }

建立一個SLinkList類來實現介面

public class SLinkList<E> implements ILinarList<E>{
    private Node<E> start;//1    新建一個空的帶頭節點
    int size;
    public
SLinkList(){ start=null; size=0; } /*一個節點中的成員變數指向一個新的Node,從例項物件的角度,整條連結串列中有例項化的物件為start, * 詳見1、2,可以看出,private Node<E> start=new Node<E>(item,null),例項化了一個start * 接下來add方法中,Node<E> current=start 為引用了start 的地址,start 的成員變數next的型別是Node<E>的引用型別, * 裡面包含一個E型別的item,和一個Node<E>型別的next * 也就是說每新增一個節點都是沒有例項化物件的,直接從start 的next成員指向一個新的Node<E>, * 再新增就是從新的Node<E>中的next成員指向新的Node<E> * 如下面的語句 */ //新增元素到連結串列的末尾 public boolean add(E item) { if(start==null)//如果帶頭節點為空,將新建一個帶頭節點 start=new Node<E>(item,null);//2 else {//如果帶頭節點不為空的話,新建一個current指向start的地址 Node<E> current=start; while(current.next!=null){//依次訪問每一個節點,當一個節點的next為空時,說明此節點為最後一個節點 current=current.next;//注意,這裡的賦值,每次都是賦予地址,並不是修改 } current.next=new Node<E>(item,null);//引用最後一個節點的next,建立一個新的節點 } size++; return true; } //插入元素到i索引位置前插入一個數據元素 public boolean add(int i, E item) { if(i<0||i>size)//等於size時候即為在末尾調加一個元素 throw new IndexOutOfBoundsException("Index:"+i+",Size:"+size);//丟擲越界異常 Node<E> newnode=new Node<E>(item, null); if(i==0){//第一個元素前插入一個元素 newnode.next=start;//newnode.next指向start的地址,此時原頭元素有了一個指向他的地址 start=newnode;//start的地址指向newnode的地址,所以此時有兩個例項物件指向帶頭元素,分別是start和newnode size++; }else{ Node<E> current=start;//將current指向頭元素的地址 Node<E> previous=null; int number=0;//定義一個number用來計算訪問節點的次數 while(number<i){//從0開始自加,加到i時候,此時current指向i的索引位置,previous指向前一個 previous=current;//previous始終儲存current前一個節點的地址 current=current.next;//迴圈訪問current的next的地址 number++;//每訪問一次number自加一次 } previous.next=newnode;//將前一個節點的地址的next指向修改為newnode newnode.next=current;//將newnode的next指向當前的節點元素 size++; } return true; } //清楚索引的元素 public E remove(int i) { E oidValue=null;//先賦值為null,兩個迴圈都沒有進入時,此方法返回一個null if(i<0||i>size-1) throw new IndexOutOfBoundsException("Index:"+i+",Size:"+size);//丟擲越界異常 else if(!isEmpty()){//當整個連結串列不為空時,進去此語句 if(i==0){//當要清楚頭元素時 oidValue=start.item;//將返回元素賦值 start=start.next; size--; }else{//以下方法同add重寫的第二次方法 Node<E> previous=null; Node<E> current=start; int number=0; while(number<i){ previous=current; current=current.next; number++; } oidValue=current.item; previous.next=current.next;//將指定元素的前一個元素的next指向指定元素的下一個元素 current.next=null;//釋放當前元素的next current=null;//同上(個人覺得不做這兩步好像也沒有什麼問題?) size--; } } return oidValue; } public int indexOf(E item) { int number=0; if(item==null){//需要單獨對item==null的情況判定,因equals沒有比較null,空指標錯誤 for(Node<E> x=start;x!=null;x=x.next){ if(x.item==null) return number; number++; } }else{ for(Node<E>x=start;x!=null;x=x.next){ if(item.equals(x.item))//判定是否為所要的元素 return number; number++; } } return -1;//當遍歷完整個連結串列之後沒有所要的元素,說明此連結串列不存在此元素,返回-1 } public E get(int i) { E item=null; if(i<0||i>size-1) throw new IndexOutOfBoundsException("Index:"+i+",Size:"+size);//丟擲越界異常 else if(!isEmpty()){ Node<E> current=start; for(int j=0;j<i;j++)//當知道要取第i個元素的時候,用for迴圈執行i次 current=current.next; item=current.item; } return item; } public int size() { return size; } public void clear() { for(Node<E> x=start;x!=null;){//當x為空時停止 Node<E> next=x.next;//儲存x.next的地址 x.item=null;//將x中的元素清空 x.next=null;//將x的指向清空,注意,x.next不代表是下一個節點,僅僅是指向下一個節點的地址 x=next; } start =null;//start也是指向一片地址,如果沒有清空的話,依然可以訪問,只不過start.item和start.next都為空罷了 size=0; } public boolean isEmpty() { return size==0; } }