數據結構—線性表(Java、C雙語言實現)

線性表

由零個或多個組成的有限序列。首先他需要是序列,當元素有多個的時候,第一元素無前驅,最後一個元素無後繼,其餘每個元素都有唯一的前驅和後繼。線性表中每個數據元素可以由若干個數據項組成。

線性表的順序存儲

用一段連續的存儲單元,依次存儲線性表中的數據元素。

線性表順序存儲結構:

#define MAXSIZE 20        /*存儲空間初始分配*/
#define ERROR 0
#define OK 1
typedef int ElemType;       /*定義數據類型,具體以實際情況*/
typedef struct{
    ElemType data[MAXSIZE];   /*使用數據存儲線性表*/
    int length;        /*線性表當前的長度*/
}

線性表查找

int GetElem(SqList *L,int i, ElemType e){
      if( L.length ==0 || i >L.length || i<1)
             return ERROR;
       e = L.data[i-1];
       return OK;
 }
時間複雜度O(1)


線性表插入

int InserList(SqList *L,int i,ElemType e){
     int k;
     if( L->length >= MASIZE )          /*當前長度大於數組規定長度*/
            return ERROR; 
     if( i <1 || i > L->legth+1)       /*插入位置不合理*/
            return ERROR;
      if(i<=L->length){                 
            for(k=L->length-1;k>i-1;k--){
                   L->data[k+1] = L->data[k];       /*將位置k後的元素全部向後移動一位*/
            }
             L->data[i-1] = e;        /*將插入的值放入第i位,下標爲i-1*/
             L->length++;             /*當前線性表長度加1*/
            return OK;
      }
}
時間複雜度爲O(n)


線性表刪除

int DeleteList(SqList *L,int i,ElemType e){
      int k;
      if(L->length == 0)         /*判斷線性表是否有元素*/
          return ERROR;
      if(i<1 || i > L->length)  /*判斷刪除位置是否合理*/
         return ERROR;
       e = L->data[i-1];
       if(i<L->length){
            for(k=i;k<L->length;k++){        /*將第i個元素之後的所有元素向前移動一個單位*/
                  L->data[i-1] = L->data[i];
            }
       }
       L->length--;
       return OK;
 }
時間複雜度O(n)

線性表的鏈式存儲

用一組任意的存儲單元存儲線性表的數據元素,這寫存儲單元可以是連續的也可以是不連續的,每個節點除了存儲數據外,還存儲指向下一個節點地址。如果每個節點同時存儲前一個節點的地址信息,則稱爲雙向鏈表。

線性表單鏈表存儲結構:

#define ERROR 0
#define OK 1
typedef int ElemType;    /* 假設ElemType類型爲intt*/
typedef struct Node{
     ElemType data;
     struct Node *next;
}Node;
typedef struct Node *LinkList; /*定義LinkList */

單鏈表的創建:

頭插法:

void CreateListHead(LinkList *L,int n){
      int i;
      LinkList p;                 /*每次新節點*/
      *L = (LinkList)malloc(sizeof(Node));
      (*L)->next = null;     /*建立帶表頭節點的單鏈表*/
       for(i=0;i<n;i++){
            p = (LinkList)malloc(sizeof(Node));
            p->data = i;        /*根據實際情況存儲數據*/
            p->next = (*L)->next;
            (*L)->next = p;
       }
}

時間複雜度O(n)


尾插法:

void CreateListTail(LinkList *L,int n){
         int i;
         LinkList p,r;
         *L = (LinkList)malloc(sizeof(Node));
         r = *L;
         for(i=0;i<n;i++){
               p = (LinkList)malloc(sizeof(Node));  /*生成新節點*/
               p->data = i;                                         /*新節點存儲數據*/
               r->next = p;                                       /*將表尾節點指向新節點*/
               r = p;                                                 /*將新節點定義爲表尾節點*/
         }
         r->next = null;              /*表示當前鏈表已經創建完畢*/
 }

時間複雜度O(n)


單鏈表讀取

int GetElem(LinkList *L,int i,ElemType e){
      int j;
      LinkList p;
      p = (*L)->next;            /*讓p指向第一個節點*/
      while(p && j<i){           /*這裏因爲之前是讓p指向第一個節點,所以這裏到達i-1時候,p已經爲第i個節點了*/
           p = p->next;
           j++;
      }
      if(!p || j>i)                  /*判斷是否存在*/
          return ERROR;
      e = p->data;
      return OK;
 }
時間複雜度O(n)


單鏈表插入

int ListInsert(LinkList *L,int i,ElemType e){
     int j;
     LinkList p,q;
     p = *L;                              /*這裏是將鏈表頭指針賦給p,即在循環中,第一次是指向第一個節點,所以到i-1時,正處在i-1節點*
     while(p && j<i){               /*這裏是將*/
            p = p->next;
            j++; 
     }
     if(!p || j>i){
            return ERROR;
     }
     q = (LinkList)malloc(sizeof(Node));
     q->data = e;
     q->next = p->next;               /*一定要現將新節點指針指向i節點,然後在將i-1節點指向新節點*/
     p->next = q;
     return OK; 
 }

單鏈表刪除

int ListDelete(LinkList *L,int i,ElemType e){
      int j;
      LinkList p,q;
      p = *L;
      while(p && j<i){
           p = p->next;
           j++;
      }
      if(!p || j>i)
           return ERROR;
      q = p->next;                       /*將要刪除的i節點賦給q*/
      p->next=q->next;              /*是i-1節點指向i+1節點*/
      e = q->data;                       /*獲取要刪除節點的data*/
      free(q);
      return OK;
 }

對於單鏈表的插入刪除,如果不知道要刪除的位置指針,也需要遍歷鏈表,但是如果無論插入刪除多少個只需掃描一次即可,其他時候的時間複雜度是O(1)


單鏈表銷燬

int ClearList(LinkList *L){
      LinkList p;
      p=(*L)->next;   /*使p指向第一個節點*/
      while(p){           /*判斷到沒到表尾*/
          q=p->next;    /*將q指向下一個節點*/
          free(p);           /*刪除當前節點*/
          p=q;               /*p指向下一個要刪除的節點*/
      }
      p->next=null;
     return OK;
 }

基於JAVA實現線性表

首先要了解java集合中Collection中的方法:http://blog.csdn.net/colin_yjz/article/details/46673383

Collection以及Collection的實現類都實現了Iterable接口,用以使用增強的for循環。並且都提供了iterator方法,返回一個Iterator類型的對象,iterator用來對數據元素進行迭代。關於Iterator與Iterable的區別可以看:http://blog.csdn.net/colin_yjz/article/details/46673275

線性表使用List中的ArrayList和LinkList來實現最佳。ArrayList是一種可增長的數組的實現,對於隨機訪問花費時間數量級是常數,缺點是插入和刪除代價非常高,因爲要移動大量的元素。LinkList則提供了ListADT的雙鏈表實現,對於插入和刪除都是常數數量級,但是get查找效率非常低。操作線性表應該儘量使用Iterator迭代器,這樣效率比使用循環效率高,對於刪除等操作應該使用Iterator中提供的remove,因爲迭代器的remove不會影響Iterator結構,如果使用List的remove會影響Iterator結構,從而刪除失敗。

對於二者List提供了ListIterator,有previous和hasPrevious方法支持向前遍歷。並且Add操作的是當前項,即迭代的previous和next之間。


線性表使用java實現可以查看博主的ArrayList源碼解析博文,因爲比較簡單,所以沒有手敲實現。


鏈表java實現,:

public class MyLinkList<E> {

	Node<E> first;		//鏈表頭節點
	Node<E> last;		//鏈表尾節點
	int size = 0;				//鏈表節點個數
	
	/**
	 * 內部靜態類,封裝節點信息(無外圍類引用,可以聲明一個靜態類,以便消除產生的引用)
	 * pref:前一節點
	 * next:後一節點、
	 * data:存儲數據區
	 */
	private static  class Node<E>{
		E data;
		Node<E> next;
		Node<E> pref;
		Node(Node<E> pref,E data,Node<E> next){
			this.pref = pref;
			this.data = data;
			this.next = next;
		}
	}
	
	/**
	 * 兩個構造方法,無參構造方法用來初始化空鏈表,有參構造方法,將集合中元素初始化到鏈表中
	 */
	public MyLinkList(){
		
	}
	
	public MyLinkList(Collection<? extends E> c) throws Exception{
		this();
		addAll(c);
	}
	
	 void linkLast(E e){
		Node<E> l = last;		//暫存尾節點
		Node<E> newNode = new Node<E>(l, e, null);		//創建一個新節點
		last = newNode;	//將指向尾節點的變量,指向新節點
		if(l == null)
			first = newNode;		//如果尾節點爲空,說明頭節點也爲null,將頭節點也要指向newNode
		else
			l.next = newNode;	//將之前尾節點指向後一節點區指向新添加的節點
		size++;
	}
	public boolean add(E e){
		linkLast(e);
		return true;
	}
	
	/**
	 * 返回指定位置節點
	 * @param index
	 * @return
	 */
	Node<E> node(int index){
		Node<E> x = first;
		for(int i=0;i<index;i++){
			x = x.next;
		}
		return x;
	}
	/**
	 * 檢查索引位置是否合法
	 * @param index
	 * @throws Exception
	 */
	void checkIndex(int index) throws Exception{
		if(index<0||index>size){
			throw new Exception("index error");
		}
	}
	/**
	 * 在非尾節點前添加一個節點
	 * @param e
	 * @param now
	 */
	void linkBefor(E e,Node<E> now){
		Node<E> p = now.pref;
		Node<E> newNode = new Node<E>(p, e, now);
		if(p == null){
			first = newNode;
		}
		else{
			p.next = newNode;
		}
		now.pref =newNode;
	}
	/**
	 * 在指定位置添加元素
	 */
	public void add(int index,E e) throws Exception{
		checkIndex(index);
		if(index == size)
			linkLast(e);
		else
			linkBefor(e, node(index));
	}

	/**
	 * 將集合元素添加到鏈表中,他默認也是調用重載方法addAll(index,c),只是在表尾添加
	 * @param c
	 * @throws Exception 
	 */
	public boolean addAll(Collection<? extends E> c) throws Exception{
		return addAll(size,c);
	}
	
	public boolean addAll(int index,Collection<? extends E > c) throws Exception{
		checkIndex(index);
		Node<E> pred;			//要插入節點位置的前一個節點
		Node<E> now;			//要好插入的節點位置
		Object[] o = c.toArray();
		int newNum = o.length;
		if(newNum == 0)
			return false;

		if(index == size){				//根據位置查找pred節點和now節點
			pred = last;
			now = null;
		}else{
			now = node(index);
			pred = now.pref;
		}
		
		for (Object oc : o) {
			@SuppressWarnings("unchecked")
			E e = (E) oc;
			Node<E> newNode = new Node<E>(pred, e, null);
			if(pred == null)			//如果插入前一個節點是null說明現在插入的位置是鏈表頭部,需要將頭節點指向當前插入及誒單
				first = newNode;
			else
				pred.next = newNode;		//將前一節點指向後節點的指針指向新節點
			pred = newNode;
		}
		
		if(now == null){		//如果當前插入節點位置是null,說明在尾部添加的節點,需要將尾節點指向
			last = pred;
		}else{
			pred.next = now;
			now.pref = pred;
		}
		size += newNum;
		return true;
	}
	
	/*
	 * 在表頭插入元素
	 */
	public void addFirst(E e){
		linkBefor(e, first);
	}
	/*
	 * 在表尾添加元素
	 */
	
	public void addLast(E e){
		linkLast(e);
	}
	/**
	 *清空鏈表中所有元素
	 */
	public void clear(){
		Node<E> x = first;
		Node<E> temp = null;
		for(int i=0;i<size;i++){
			temp = x.next;
			x.data = null;
			x.next = null;
			x.pref = null;
			x = temp;
		}
		size = 0;
		first = last = null;
	}
	
	/**
	 * 查找指定元素的位置 
	 */
	public int indexOf(Object o){
		Node<E> x = first;
		if( o == null){					//null比較與其他比較不同
			for(int i =0 ;i<size;i++){
				if(x.data == null){
					return i;
				}
				x = x.next;
			}
		}
		else{
			for(int i=0;i<size;i++){
				if(o.equals(x.data)){
					return i;
				}
				x = x.next;
			}
		}
		return -1;		//如果沒有找到返回-1
	}
	
	/**
	 * 判斷是否包含一個指定元素,就是判斷其位置
	 */
	
	public boolean contains(Object o){
		return indexOf(o) != -1;
	}
	
	/**
	 *獲取指定位置元素
	 * @throws Exception 
	 */
	public E get(int index) throws Exception{
		checkIndex(index);
		return node(index).data;
	}
	
	/**
	 * 刪除表頭元素
	 */
	public E removeFirst(){
		Node<E> f = first;
		Node<E> next = f.next;
		E element = f.data;
		f.data = null;
		f.next = null;
		first = next;
		if(next == null)
			last = null;
		else
			next.pref = null;
		size--;
		return element;
	}
	/**
	 * 刪除表尾元素
	 */
	public E removeLast(){
		Node<E> t = last;
		Node<E> p = last.pref;
		E element = t.data;
		t.data = null;
		t.pref = null;
		last = p;
		if(p == null)
			first = null;
		else
			p.next = null;
		size--;
		return element;
	}
	/**
	 * 刪除指定元素
	 */
	public boolean  remove(Object o){
		Node<E> x = first;
		int index = -1;
		if(o == null){
			for(int i =0;i<size;i++){
				if(x.data == null){
					index = i;
				}
				x = x.next;
			}
		}else{
			for(int i=0;i<size;i++){
				if(o.equals(x.data)){
					index = i;
				}
				x = x.next;
			}
		}
		if(index == -1){
			return false;
		}else{
			Node<E> now = node(index);
			Node<E> p = now.pref;
			Node<E> n = now.next;
			if(p == null){
				first = n;
			}else{
				p.next = n;
				now.pref = null;
			}
			if(n == null){
				last =  p;
			}else{
				n.pref = p;
				now.next = null;
			}
			now.data = null;
			size--;
			return true;
		}
	}
	/**
	 * 修改指定位置元素
	 * @throws Exception 
	 */
	public E set(int index,E element) throws Exception{
		checkIndex(index);
		Node<E> x = node(index);
		E oldEle = x.data;
		x.data = element;
		return oldEle;
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章