1. 程式人生 > >java 實現線性表

java 實現線性表

一、概念

對於常用的資料結構,可分為線性結構和非線性結構,線性結構主要是線性表,非線性結構主要是數和圖。當n>0時,表可表示為:(a0,a1,a2,a3,…an)

1、 線性表的特徵:

1、存在唯一的被稱作”第一個”的資料元素

2、存在唯一的一個稱作”最後一個的”資料元素”

3、除第一個之外,集合中的每個資料元素均只有一個前驅

4、除最後一個之外,集合中每個元素均只有一個後繼

2、線性表的基本操作

         1、初始化:

         2、返回線性表長度

         3、獲取指定索引處元素

         4、按值查詢元素位置

         5、直接插入資料元素

         6、向指定位置插入元素

         7、直接刪除元素

         8、刪除指定位置元素

二、順序儲存結構

         線性表的順序結構是指用一組地址連續的儲存單元依次存放線性表的元素。下面採用陣列實現順序結構線性表。

import java.util.Arrays;

public class Sequence<T> {
	private Object[] elementData; <span style="color: rgb(0, 153, 0); font-family: Arial;">//定義一個數組</span>
	private int DEFAULT_SIZE = 1;  <span style="color:#009900;">//陣列預設大小</span>
	private int capacity;  <span style="color:#009900;">//陣列容量</span>
	private int size = 0;  <span style="color:#009900;">//當前陣列大小</span>
	//初始化
	public Sequence(){
		capacity = this.DEFAULT_SIZE;
		elementData = new Object[capacity];
	}
	
	public Sequence(T element){
		this();
		elementData[0] = element;
		size++;
	}
	
	<span style="color:#009900;">//返回線性表長度</span>
	public int length(){
		return this.size;
	}
	
	<span style="color:#009900;">//返回指定索引處元素。</span>
	public T getElementByIndex(int index){
		
		if(index < 0 || index > (size-1)){
			System.out.println("索引範圍越界!!!");
			System.exit(0);
		}
		return (T)elementData[index];
	}
	<span style="color:#009900;">//按值查詢資料元素的位置</span>
	public int getIndexByValue(T value){
		for(int i = 0; i < elementData.length;i++ ){
			if(value.equals(elementData[i])){
				return i;
			}
		}
		return -1;<span style="color:#009900;">//未找到則返回-1</span>
	}
	
	<span style="color:#009900;">//向指定位置插入元素</span>
	public void insert(T element,int index){
		ensureCapacity();  <span style="color:#009900;">//確保線性表容量夠</span>
		if(index >= 0 && index < size){
			int i = 0;
			<span style="color:#009900;">//將插入位置之後元素挨個後移1</span>
			for(i = (size-1); i >= index;i--){
				elementData[i+1] = elementData[i];
			}
			elementData[i+1] = element; <span style="color:#009900;">//插入該元素</span>
			size++;  <span style="color:#009900;">//陣列當前容量+1</span>
		}
		else{
			throw new IndexOutOfBoundsException("插入元素位置越界!!!");
		}
	}
	
	<span style="color:#009900;">//想線性表末尾新增元素</span>
	public void add(T element){
		ensureCapacity();  <span style="color:#009900;">//確保線性表容量夠</span>
		elementData[size] = element;
		size++;
	}
	
	<span style="color:#009900;">//刪除線性表中指定位置元素</span>
	public void delete(int index){
		if(index >= 0 && index < size){
			int i;
			<span style="color:#009900;">//將要刪除元素位置之後的元素挨個前移1,通過覆蓋刪除</span>
			for(i = index+1;i < size;i++){
				elementData[i-1] = elementData[i];
			}
			elementData[size-1] = null;
			
		}
		else{
			throw new IndexOutOfBoundsException("所要刪除元素位置越界!!!");
		}
	}
	
	<span style="color:#009900;">//刪除指定元素</span>
	public void delete(T value){
		int index = this.getIndexByValue(value);
		if(index != -1){
			this.delete(index);
		}
		else{
			System.out.println("您要刪除的元素並不存在");
			System.exit(0);
		}
		size--;
	}
	
	<span style="color:#009900;">//判斷線性表是否為空</span>
	public boolean isEmpty(){
		boolean b = false;
		if(this.length() != 0){
			b = true;
		}
		return b;
	}
	
	<span style="color:#009900;">//清空線性表</span>
	public void clear(){
		for(Object o:elementData){
			o = null;
		}
		size = 0;
	}
	
	<span style="color:#009900;">//顯示線性表中所有元素</span>
	public void view(){
		System.out.print("當前線性表中元素為:");
		for(int i = 0;i < size;i++){
			System.out.print(elementData[i] + " ");
		}
		System.out.print("\n");
	}
	
	<span style="color:#009900;">//擴充線性表容量</span>
	public void ensureCapacity(){
		while((size+1) > capacity){
			capacity= capacity * 2;  <span style="color:#009900;">//線性表容量每次增大一倍</span>
			elementData = Arrays.copyOf(elementData, capacity);
		}
	}
	
	public static void main(String[] args) {
		Sequence<String> sequence = new Sequence<>();
		sequence.add("hello");
		sequence.add("world");
		sequence.add("java");
		sequence.add("perfect");
		sequence.view();
		sequence.insert("haha", 1);
		sequence.view();
		System.out.println("索引為3的元素為:" + sequence.getElementByIndex(3));
		System.out.println("字串perfect的索引號為:" + sequence.getIndexByValue("perfect"));
		sequence.delete("hello");
		sequence.view();
		sequence.clear();
		System.out.println("clear之後線性表長度為:" + sequence.length());	
	}
}

三、鏈式儲存結構

1、概念

鏈式儲存結構的線性表(簡稱為連結串列)採用一組任意的儲存單元存放線性表中的資料元素。鏈式儲存結構的線性表不是按線性的邏輯順序來儲存資料元素,它需要在每個資料元素裡儲存一個引用下一個資料元素的引用。

         節點 = 資料元素 + 引用下一個節點的引用 + 引用上一個節點的引用

2、單鏈表基本操作

建立單鏈表方法:1頭插法建表  2尾插法建表

查詢操作:1按index查詢指定資料元素  2在連結串列中查詢指定的資料元素的index

插入操作:在第index個索引處插入元素

刪除操作:刪除第index個節點

3、單鏈表具體實現

public class LinkList<T>{
	<span style="color:#009900;">//定義Node節點</span>
	private class Node{
		private T data;
		private Node next;
		
		public Node(){
			
		}
		public Node(T element,Node next){
			this.data = element;
			this.next = next;
		}
	}
	<span style="color:#009900;">//成員變數</span>
	private Node header; <span style="color:#009900;">//頭節點</span>
	private Node tail;  <span style="color:#009900;">//尾節點</span>
	private int size = 0;  <span style="color:#009900;">//連結串列長度</span>
	
	public LinkList(){
		header = null;
		tail = header;
	}
	
	public LinkList(T element){
		header = new Node(element, null);
		tail = header;
	}
	
	<span style="color:#009900;">//獲取連結串列中指定索引處的元素</span>
	public T get(int index){
		return this.getNodeByIndex(index).data;
	}
	
	
	<span style="background-color: rgb(0, 153, 0);">//獲取連結串列中指定索引處Node</span>
	public Node getNodeByIndex(int index){
		this.checkBorder(index);
		Node currentNode = header;
		for(int i = 0;i < size && currentNode != null;i++,currentNode = currentNode.next){
			if(i == index){
				return currentNode;
			}
		}
		return null;
	}
	
	<span style="background-color: rgb(255, 255, 255);"><span style="color:#009900;">//向指定索引處插入元素</span></span>
	public void insert(T element,int index){
		this.checkBorder(index);
		if(index == 0){
			this.addAtHeader(element);
		}
		else{
			Node prevNode = this.getNodeByIndex(index-1);//獲取插入位置的前向Node
			prevNode.next = new Node(element,prevNode.next);
		}
		size++;
	}
	
	<span style="color:#009900;">//刪除指定索引處Node</span>
	public T delete(int index){
		this.checkBorder(index);
		Node del = null;
		//刪除的是header
		if(index == 0){
			del = header;
			header = header.next;
		}
		else{
			Node prevNode = this.getNodeByIndex(index);
			del = prevNode.next;
			prevNode.next = del.next; //將prevNode的後向Node設定為del.next
			del.next = null;
		}
		size--;
		return del.data;
	}
	
	<span style="color:#009900;">//頭插法向連結串列中新增元素</span>
	public void addAtHeader(T element){
		header = new Node(element,header);//將新新增的Node的next設定為原先的header,然後將新的Node設定為新的header
		if(tail == null){
			tail = header;
		}
		size++;
	}
	
	<span style="color:#009900;">//尾插法</span>
	public void add(T element){
		//連結串列為空的情況
		if(header == null){
			header = new Node(element, null);
			tail = header;
		}
		else{
			tail.next = new Node(element, null); //將tail節點的next設定為new Node
			tail = tail.next; //將new Node設定為tail
		}
		size++;
	}
	<span style="color:#009900;">//遍歷整個連結串列</span>
	public void view(){
		Node currentNode = header;
		System.out.print("當前連結串列元素:");
		while(currentNode != null){
			System.out.print(currentNode.data + " ");
			currentNode = currentNode.next;
		}
		System.out.println("");
		
	}
	
	<span style="color:#009900;">//檢測索引是否越界</span>
	private void checkBorder(int index){
		if(index < 0 || index > size-1){
			throw new IndexOutOfBoundsException("連結串列索引已越界");
		}
	}
	
	public int length(){
		return this.size;
	}
	
	public static void main(String args[]){
		LinkList<String> linkList = new LinkList<>();
		linkList.add("hello");
		linkList.add("world");
		linkList.addAtHeader("header");
		System.out.println("當前連結串列長度為:" + linkList.length());
		linkList.view();
		System.out.print("插入test之後,");
		linkList.insert("test",2);
		linkList.view();
		linkList.delete(2);
		System.out.print("刪除索引2處元素後,");
		linkList.view();
		System.out.println("索引1處元素為:" + linkList.get(1));
	}
}


4、雙鏈表實現

public class DoubleLinkList<T> {
	
	<span style="color:#009900;">//定義雙向連結串列節點</span>
	private class Node{
		private T data;
		private Node prev;
		private Node next;
		public Node(){
			
		}
		public Node(T element,Node prev,Node next){
			this.data = element;
			this.prev = prev;
			this.next = next;
		}
	}
	
	private Node header;
	private Node tail;
	private int size = 0;
	
	public DoubleLinkList(){
		header = null;
		tail = null;
	}
	
	public DoubleLinkList(T element){
		header = new Node(element,null,null);
		tail = header;
		size++;
	}
	<span style="color:#009900;">//獲取連結串列長度</span>
	public int length(){
		return this.size;
	}
	
	<span style="color:#009900;">//檢測index是否越界</span>
	public void checkBorder(int index){
		if(index < 0 || index > size-1){
			throw new IndexOutOfBoundsException("連結串列索引已越界");
		}
	}
	
	<span style="color:#009900;">//獲取指定索引處Node</span>
	public Node getNodeByIndex(int index){
		checkBorder(index);//越界檢測
		if(index < size/2){
			Node currentNode = header;
			for(int i = 0;i < size/2;i++,currentNode = currentNode.next ){
				if(i == index){
					return currentNode;
				}
			}
		}
		else{
			Node currentNode = tail;
			for(int i = size-1;i >= size/2;i--,currentNode = currentNode.prev){
				if(i == index){
					return currentNode;
				}
			}
		}
		return null;
	}
	
	<span style="color:#009900;">//獲取連結串列中指定索引處的元素值</span>
	public T get(int index){
		return this.getNodeByIndex(index).data;
	}
	
	<span style="color:#009900;">//根據元素值查詢元素索引</span>
	public int locate(T element){
		Node currentNode = this.header;
		for(int i = 0;i < size-1;i++,currentNode = currentNode.next){
			if(currentNode.data.equals(element)){
				return i;
			}
		}
		return -1;
			
	}
	
	<span style="color:#009900;">//向連結串列中以尾插法新增元素</span>
	public void add(T element){
		if(size == 0){
			header = new Node(element,null,null);
			tail = header;
		}
		else{
			Node newNode = new Node(element,tail,null);
			tail.next = newNode;
			tail = newNode;
		}
		size++;
	}
	
	<span style="color:#009900;">//頭插法向連結串列新增元素</span>
	public void addAtHeader(T element){
		if(size == 0){
			header = new Node(element,null,null);
			tail = header;
		}
		else{
			Node newNode = new Node(element,null,header);
			header.prev = newNode;
			header = newNode;
		}
		size++;
	}
	
	
	<span style="color:#009900;">//根據索引插入元素</span>
	public void insert(T element,int index){
		this.checkBorder(index);
		Node prevNode = this.getNodeByIndex(index-1);
		Node nextNode = this.getNodeByIndex(index);
		Node insertNode = new Node(element, prevNode, nextNode);
		nextNode.prev = insertNode;
		prevNode.next = insertNode;
		size++;
	}
	
	<span style="color:#009900;">//根據索引刪除元素</span>
	public void delete(int index){
		this.checkBorder(index);
		Node prevDelNode = this.getNodeByIndex(index-1);
		Node nextDelNode = this.getNodeByIndex(index+1);
		prevDelNode.next = nextDelNode;
		nextDelNode.prev = prevDelNode;
		size--;
	}
	
	<span style="color:#009900;">//遍歷連結串列中元素</span>
	public void view(){
		System.out.print("當前連結串列中元素為:");
		for(int i = 0;i < size;i++){
			System.out.print(this.get(i) + " ");
		}
		System.out.println();
	}
	
	public static void main(String[] args) {
		DoubleLinkList<String> doubleLinkList = new DoubleLinkList<>();
		doubleLinkList.add("hello");
		doubleLinkList.add("world");
		doubleLinkList.insert("test", 1);
		doubleLinkList.addAtHeader("first");
		doubleLinkList.view();
		System.out.println("索引為0處的元素值為:" + doubleLinkList.get(0));
		System.out.println("test字串在連結串列中索引號為: " + doubleLinkList.locate("test"));
		doubleLinkList.delete(1);
		System.out.print("刪除索引號為1元素後,");
		doubleLinkList.view();
	}

}


 注:本文部分內容參考自《瘋狂Java程式設計師的基本修養》和《資料結構(C語言版)》