1. 程式人生 > >《java常用演算法手冊》 第二章 資料結構 順序表 單鏈表

《java常用演算法手冊》 第二章 資料結構 順序表 單鏈表

資料元素:例如單向連結串列的一個節點  擁有 頭指標和資料兩個資料組成

 

四種儲存方式 :

 

 

 

 

 

 

 

 

 

順序表的實現 :

package LineStructure;

//順序表
public class SeqList<T> extends Object {

	// 表長
	private int length;

	// 節點元素
	private Object[] element;

	// 空構造 預設容量的空表
	public SeqList() {
		this(64);
	}

	// 初始化 構造容量為length的空表
	public SeqList(int length) {
		this.length = 0;
		this.element = new Object[length];
	}

	// 構造有元素的順序表
	public SeqList(T ele[]) {
		this(ele.length);
		// 複製元素到順序表中
		for (int i = 0; i < ele.length; i++) {
			element[i] = ele[i];
		}
	}

	// 判斷是否為空表
	public boolean isEmpty() {
		return this.length == 0;
	}

	// 返回 長度
	public int size() {
		return this.length;
	}

	// 返回順序表所有元素的描述字串,形式為“(,)” 覆蓋toString方法
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("{");
		sb.append(this.element[0]);
		for (int i = 1; i < this.length; i++) {
			sb.append(","+this.element[i]);
		}
		
		sb.append("}");
		return sb.toString();
	}

	// 查詢節點 返回第i個元素
	public T get(int i) {
		if (i > 0 && i < this.length) {
			return (T) this.element[i];
		} else {
			return null;
		}
	}

	// 修改第i個元素 注意並不是插入元素
	public void set(int i, T value) {
		if (value == null) {
			throw new NullPointerException("sorry x == null");
		} else if (i > 0 && i < this.length) {
			this.element[i] = value;
		} else {
			throw new java.lang.IndexOutOfBoundsException("Sorry your element :" + i + " IndexOutOfBounds");
		}
	}

	// 插入元素
	public String insert(int i, T value) {
		if (value == null) {
			throw new NullPointerException("x == null");
		} else if (i < 0) {// 插入到最前端
			i = 0;
			// this.element[0] = value;
		} else if (i > this.length) {// 插入到最後端
			i = this.length;
			// this.element[this.length] = value;
		}

		// 由於無法直接擴容 element2臨時存放值錢的元素
		Object[] elementTemp = this.element;
		
		// 擴容 重新開闢空間存放元素
		if (i > this.length) {
			this.element = new Object[elementTemp.length * (2 / 3)];
		}
		// 賦值插入位置之前的元素
		// 前i-1個元素給新的element
		for (int j = 0; j < i; j++) {
			this.element[j] = elementTemp[j];
		}
		// 移動插入位置之後的元素
		// 插入到中間 i之後的元素後移 順序為從前向後,也可以從後向前 
		//錯誤 只能從後向前 elementTemp是this.element的引用 不是副本
		/*for (int j = i; j < elementTemp.length-1; j++) {
			this.element[j + 1] = elementTemp[j];
		}*/
		//從後向前
		for(int j=this.length-1;j>=i;j--){
			this.element[j+1] = elementTemp[j] ;
		}
		
		// 插入元素
		this.element[i] = value;
		this.length++;
		return "insert success element" + value + "insert into position: " + i;
	}

	// 預設插入 插入到表最後
	public String insert(T value) {
		return insert(this.length, value);
	}

	// 移除元素
	public String remove(int i) {
		if (i >= 0 && i < this.length && this.length > 0) {
			// i之後元素向前移動
			for (int j = i; j < this.length - 1; j++) {
				this.element[j] = this.element[j + 1];
			}
			// 注意:最後一個元素設定為空
			this.element[this.length - 1] = null;
			this.length--;
		} else {
			return null;
		}
		return "success";
	}

	// 清除
	public void clear() {
		for (int j = 0; j < this.length; j++) {
			this.element[j] = null;
		}
		this.length = 0;
	}

	// 查詢元素 返回序號
	public int search(T value) {
		for (int i = 0; i < this.length; i++) {
			if (value == this.element[i]) {
				return i;
			}
		}
		return -1;
	}

	public boolean contains(T value) {
		return this.search(value) != -1;
	}

}

 

 

 

 

單鏈表實現 :

package LineStructure;

public class LinkedList<T> extends Object {

	// 理解java引用 http://zwmf.iteye.com/blog/1738574

	// 兩種思路 第一種插入節點(包含資料)
	// 參考 https://www.cnblogs.com/whgk/p/6589920.html
	// 第二種插入資料,需要new 節點,感知不到節點的存在
	// https://blog.csdn.net/jianyuerensheng/article/details/51200274

	// 每一個節點存放下一個節點的引用
	public class Node {
		private Object data;
		// 存放下一個節點的引用
		private Node next;

		// Node的構造
		public Node() {
			data = null;
		}

		// Node的構造
		public Node(T data) {
			this.data = data;
		}
	}

	// 頭節點 的Data 一般是不儲存資料的
	private Node head; // 頭引用(指標)
	private Node rear; // 尾引用(指標)
	private Node point; // 臨時引用(指標)
	private int length; // 連結串列長度

	// 連結串列類的構造方法,只構造出不含資料的頭結點。 此時尾引用指向頭引用 構成一個完整的連結串列
	// 頭節點 的Data 一般是不儲存資料的
	public LinkedList() {
		head = new Node();
		rear = head;
		length = 0;
	}

	// 增加節點
	public void addNode(Node node) {
		// 連結串列中已有節點 需要遍歷到最後一個節點
		Node temp = head; // 一個移動的指標(遍歷指標)(從頭節點開始遍歷)
		// 如果連結串列是空的則 temp為head,head之後追加Node
		while (temp.next != null) { // 遍歷單鏈表,直到遍歷到最後一個則跳出迴圈。
			temp = temp.next; // 遍歷指標往後移一個結點,指向下一個結點。
		}
		temp.next = node; // temp為最後一個結點或者是頭結點,將其next指向新結點 這樣頭節點中沒有資料
	}

	// 插入指定位置
	// 前一個結點 當前位置 後一個結點
	// temp temp.next temp.next.next
	public void insertNodeByIndex(int index, Node node) {
		int position = 1;
		Node temp = head;
		while (temp.next != null) {
			if (index == position) {
				// 插入節點指向之前temp的next
				node.next = temp.next;
				// temp的next指向node
				temp.next = node;
				return;// 注意return 減少時間複雜度
			}
			position++;
			temp = temp.next;// 指標後移 對temp的賦值不會影響整個連結串列
		}
	}

	// 刪除節點
	public void delNodeByIndex(int index) {
		int position = 1;
		Node temp = head;// 指標 當前節點

		// 之前寫法 錯誤: while條件有誤 temp.next 可能為空
		/*
		 * while (temp.next != null) { if (index == position) { temp.next =
		 * temp.next.next; // 對temp的賦值不會影響整個連結串列(temp為臨時指標) 但是對temp.next賦值影響了連結串列的指標
		 * return;// 注意return 減少時間複雜度 } position++; temp = temp.next; //
		 * 對temp的賦值不會影響整個連結串列(temp為臨時指標) 但是對temp.next賦值影響了連結串列的指標
		 * 
		 * }
		 */
		// 修改while條件
		while (index != position) {
			position++;
			temp = temp.next; // 對temp的賦值不會影響整個連結串列(temp為臨時指標) 但是對temp.next賦值影響了連結串列的指標
		}
		temp.next = temp.next.next; // 對temp的賦值不會影響整個連結串列(temp為臨時指標) 但是對temp.next賦值影響了連結串列的指標
		return;// 注意return 減少時間複雜度

	}

	// 計算長度
	public int getLength() {
		int position = 0;
		Node temp = head;// 指標 當前節點
		while (temp.next != null) {
			position++;
		}
		temp = temp.next;
		return position;
	}

	// 按下標查詢節點
	// 頭節點 的Data 一般是不儲存資料的
	public T find(int position) {
		// 0為頭節點 沒有資料
		int start = 0;
		Node temp = head;
		while (position != start) {
			temp = temp.next;
			start++;
		}
		return (T) temp.data;

	}

	// 查詢元素的值,返回下標
	// 頭節點 的Data 一般是不儲存資料的
	public int search(T value) {
		int start = 1;
		Node temp = head;

		// 之前的寫法 錯誤 while條件錯誤 尾節點的temp.next可能為空!!
		/*
		 * while(temp.next != null) { if(temp.next.data == value) { return start; }
		 * start++; temp = temp.next;
		 * 
		 * }
		 */
		while (temp.next.data != value) {
			start++;
			temp = temp.next;
		}
		return start;

	}

	// 遍歷單鏈表,列印所有data
	// 頭節點 的Data 一般是不儲存資料的
	public String toString() {
		Node temp = head;
		StringBuffer sb = new StringBuffer();
		sb.append("headNode");
		while (temp.next != null) {
			sb.append("," + temp.next.data);
			temp = temp.next;
		}
		return sb.toString();
	}

	// 連結串列sort
	// 關於sort:https://www.cnblogs.com/whgk/p/6596787.html
	public void selectSort() {
		Node temp = head;// 外層指標
		while (temp.next != null) {
			Node temp2 = temp;// 內層指標
			while (temp2.next != null) {
				if ((int) temp.next.data > (int) temp2.next.data) {
					int tempData = (int) temp.next.data;
					temp.next.data = temp2.next.data;
					temp2.next.data = tempData;
				}
				temp2 = temp2.next;
			}
			temp = temp.next;
		}
	}

}