一、線性表的抽象數據類型表述
線性表的結構簡單,長度允許動態增長或搜索;可以對線性表中的任何數據元素進行訪問和查找;允許進行數據的插入和刪除操作;求線性表中的指定數據的前驅和后繼;合並線性表以及拆分線性表中。
Java JDK中有ArrayList和LinkedList兩個類很好的實現了順序存儲和鏈式存儲。因此學習數據結構的最好方式是去研究JDK源碼。
這里的代碼個人作為練習,為了便於理解,很多地方處理的並非十分嚴謹,僅供參考。轉載注明出處,技術討論 email: <yaoyao0777@Gmail.com>
1 package org.yohhan.data_structure.api; 2 3 /** 4 * @author yohhan <yaoyao0777@Gmail.com> 5 * @date create:2016年1月10日 下午4:05:35 6 * 7 * 線性表的抽象數據類型 8 * 9 */ 10 public interface MyList { 11 public void clear(); 12 13 public boolean isEmpty(); 14 15 public int length(); 16 17 public Object get(int i) throws Exception; 18 19 public void insert(int i, Object obj) throws Exception; 20 21 public void remove(int i) throws Exception; 22 23 public int indexOf(Object obj); 24 25 public void display(); 26 }
二、線性表的順序存儲實現
1.順序表的定義:
順序存儲采用一組地址連續的存儲單元依次存儲線性表占用的各個數據元素的存儲結構。
2.順序表的特點:
1)邏輯上相鄰的數據元素,在物理存儲位置上也是相鄰的。
2)存儲密度高,事先需要分配足夠應用的存儲空間。
3)隨機存取,查詢速度快,直接訪問地址單元中的數據。時間復雜度 O(1)
4)插入刪除操作會引起大量的數據移動,時間復雜度O(n)
3.順序表的結構類描述:
1 package org.yohhan.data_structure.linear; 2 3 import org.yohhan.data_structure.api.MyList; 4 5 /** 6 * @author yohhan <yaoyao0777@Gmail.com> 7 * @date create:2016年1月10日 下午4:09:15 8 * 9 * 線性表的順序存儲實現 10 */ 11 public class SqList implements MyList { 12 13 private Object[] listElem; // 數組作為線性表的存儲空間 14 private int curLen; // 線性表的當前長度 15 16 public SqList(int maxSize) { 17 curLen = 0; 18 listElem = new Object[maxSize]; 19 } 20 21 @Override 22 public void clear() { 23 curLen = 0; 24 } 25 26 @Override 27 public boolean isEmpty() { 28 return curLen == 0; 29 } 30 31 @Override 32 public int length() { 33 return curLen; 34 } 35 36 @Override 37 public Object get(int i) throws Exception { 38 if (i < 0 || i > curLen - 1) 39 throw new Exception("元素不存在"); 40 return listElem[i]; 41 } 42 43 @Override 44 public void insert(int i, Object obj) throws Exception { 45 if (curLen == listElem.length) 46 throw new Exception("存儲空間已滿"); 47 if (i < 0 || i > curLen) 48 throw new Exception("插入位置不合法"); 49 for (int j = curLen; j > i; j--) 50 listElem[j] = listElem[j - 1]; 51 listElem[i] = obj; 52 ++curLen; 53 } 54 55 @Override 56 public void remove(int i) throws Exception { 57 if (i < 0 || i > curLen - 1) 58 throw new Exception("刪除位置不合法"); 59 for (int j = i; j < curLen; j++) 60 listElem[j] = listElem[j + 1]; 61 --curLen; 62 } 63 64 @Override 65 public int indexOf(Object obj) { 66 int j = 0; 67 while (j < curLen && !listElem[j].equals(obj)) 68 j++; 69 if (j < curLen) 70 return j; 71 return -1; 72 } 73 74 @Override 75 public void display() { 76 for (int j = 0; j < curLen; j++) 77 System.out.print(listElem[j] + ", "); 78 } 79 80 @Override 81 public String toString() { 82 StringBuffer sb = new StringBuffer(); 83 sb.append("["); 84 for (Object obj : listElem) { 85 if (null != obj) 86 sb.append(obj.toString() + ", "); 87 } 88 sb.delete(sb.length() - 2, sb.length()); 89 sb.append("]"); 90 return sb.toString(); 91 } 92 93 }
三、線性表的鏈式存儲實現
1.單鏈表的定義:
采用鏈式存儲方式存儲的線性表,鏈表中每一個結點中包含存放數據元素值的數據域和存放邏輯上相鄰結點的指針域。(示例中的結點只包含一個指針域,稱為單鏈表(Single Linked List))
(圖片摘自網上)
單鏈表通過指向后繼結點的指針將結點串聯成一條鏈。
以線性表中的第一個數據元素的存儲地址作為線性表的起始地址,稱為線性表的頭指針。通過頭指針(head)來唯一標識一個鏈表。
單鏈表中的最后一個節點沒有后繼,指針域為空指針(null),稱為尾結點。
示例中采用一個“虛頭結點”數據域不存放具體值,指針域中的指針指向單鏈表的第一個結點(首結點)。即當頭結點中的指針域為空時,鏈表為空
2.鏈式存儲的特點:
1)不需要預先分配存儲空間,動態分配存儲空間,存儲密度較低、
2) 無法隨機查詢,需要從頭遍歷來查找元素。時間復雜度O(n)
3)便於進行數據的插入和刪除。時間復雜度O(1)
3.線性表的單鏈表實現:
結點類結構:
1 package org.yohhan.data_structure.node; 2 3 /** 4 * @author yohhan <yaoyao0777@Gmail.com> 5 * @date create:2016年1月10日 下午4:39:15 6 * 7 * 鏈表的結點類描述 8 * 9 */ 10 public class Node { 11 12 private Object data; 13 private Node next; 14 15 public Node() { 16 this(null, null); 17 } 18 19 public Node(Object data) { 20 this(data, null); 21 } 22 23 public Node(Object data, Node next) { 24 super(); 25 this.data = data; 26 this.next = next; 27 } 28 29 public Object getData() { 30 return data; 31 } 32 33 public void setData(Object data) { 34 this.data = data; 35 } 36 37 public Node getNext() { 38 return next; 39 } 40 41 public void setNext(Node next) { 42 this.next = next; 43 } 44 45 }
單鏈表類的描述:
1 package org.yohhan.data_structure.linear; 2 3 import org.yohhan.data_structure.api.MyList; 4 import org.yohhan.data_structure.node.Node; 5 6 /** 7 * @author yohhan <yaoyao0777@Gmail.com> 8 * @date create:2016年1月10日 下午4:51:58 9 * 10 * 帶頭結點的單鏈表實現 11 * 12 */ 13 public class LinkList implements MyList { 14 15 private Node head; 16 17 public LinkList() { 18 head = new Node(); 19 } 20 21 public LinkList(int n, boolean order) throws Exception { 22 this(); 23 if (order) 24 createFromTail(n); 25 else 26 createFromHead(n); 27 } 28 29 private void createFromTail(int n) throws Exception { 30 // 可在此添加輸入流,傳入數據 31 32 for (int j = 0; j < n; j++) 33 insert(length(), j + 1); 34 } 35 36 private void createFromHead(int n) throws Exception { 37 // 可在此添加輸入流,傳入數據 38 39 for (int j = 0; j < n; j++) 40 insert(0, j + 1); 41 } 42 43 @Override 44 public void clear() { 45 head.setData(null); 46 head.setNext(null); 47 } 48 49 @Override 50 public boolean isEmpty() { 51 return head.getNext() == null; 52 } 53 54 @Override 55 public int length() { 56 Node node = head.getNext(); 57 int length = 0; 58 while (node != null) { 59 node = node.getNext(); 60 ++length; 61 } 62 return length; 63 } 64 65 /** 66 * 按位序號查找算法 67 */ 68 @Override 69 public Object get(int i) throws Exception { 70 Node node = head.getNext(); 71 int j = 0; 72 while (node != null && j < i) { 73 node = node.getNext(); 74 ++j; 75 } 76 if (j > i || node == null) 77 throw new Exception("元素不存在"); 78 return node.getData(); 79 } 80 81 /** 82 * 在index前插入新結點 83 */ 84 @Override 85 public void insert(int i, Object obj) throws Exception { 86 Node node = head; 87 int j = -1; 88 while (node != null && j < i - 1) { 89 node = node.getNext(); 90 ++j; 91 } 92 if (j > i - 1 || node == null) 93 throw new Exception("插入位置不合法"); 94 Node newNode = new Node(obj); 95 newNode.setNext(node.getNext()); 96 node.setNext(newNode); 97 } 98 99 @Override 100 public void remove(int i) throws Exception { 101 Node node = head; 102 int j = -1; 103 while (node.getNext() != null && j < i - 1) { // 鏈表不能為空 104 node = node.getNext(); 105 ++j; 106 } 107 if (j > i - 1 || node == null) 108 throw new Exception("刪除位置不合法"); 109 node.setNext(node.getNext().getNext()); 110 } 111 112 /** 113 * 按值查找算法 114 */ 115 @Override 116 public int indexOf(Object obj) { 117 Node node = head.getNext(); 118 int j = 0; 119 while (node != null && !node.getData().equals(obj)) { 120 node = node.getNext(); 121 ++j; 122 } 123 if (node != null) 124 return j; 125 return -1; 126 } 127 128 @Override 129 public void display() { 130 Node node = head.getNext(); 131 while (node != null) { 132 System.out.print(node.getData() + ""); 133 node = node.getNext(); 134 } 135 System.out.println(); 136 } 137 138 @Override 139 public String toString() { 140 StringBuffer sb = new StringBuffer(); 141 sb.append("["); 142 Node node = head.getNext(); 143 while (node != null) { 144 sb.append(node.getData().toString() + ", "); 145 node = node.getNext(); 146 } 147 sb.delete(sb.length() - 2, sb.length()); 148 sb.append("]"); 149 return sb.toString(); 150 } 151 152 }
附:線性表的單元測試類:
1 package org.yohhan.data_structure.test; 2 3 import static org.junit.Assert.*; 4 import org.junit.Test; 5 import org.yohhan.data_structure.linear.LinkList; 6 import org.yohhan.data_structure.linear.SqList; 7 8 /** 9 * @author yohhan <yaoyao0777@Gmail.com> 10 * @date create:2016年1月10日 下午4:25:12 11 * 12 * 線性表單元測試類 13 * 14 */ 15 public class LinearTest { 16 17 @Test 18 public void sqListTest() throws Exception { 19 SqList sqList = new SqList(10); 20 for (int i = 0; i < 5; i++) 21 sqList.insert(i, i + 1); 22 System.out.println(sqList); 23 assertTrue(sqList.toString().equals("[1, 2, 3, 4, 5]")); 24 assertTrue(sqList.length() == 5); 25 assertTrue(sqList.indexOf(2) == 1); 26 assertTrue(sqList.get(0).equals(1)); 27 sqList.remove(1); 28 assertTrue(sqList.length() == 4); 29 assertTrue(sqList.indexOf(1) == 0); 30 } 31 32 @Test 33 public void linkListTest() throws Exception { 34 LinkList linkList = new LinkList(5, true); 35 System.out.println(linkList); 36 assertTrue(new LinkList(5, false).toString().equals("[5, 4, 3, 2, 1]")); 37 assertTrue(linkList.toString().equals("[1, 2, 3, 4, 5]")); 38 assertTrue(linkList.length() == 5); 39 assertTrue(linkList.indexOf(2) == 1); 40 assertTrue(linkList.get(0).equals(1)); 41 linkList.remove(1); 42 assertTrue(linkList.length() == 4); 43 assertTrue(linkList.indexOf(1) == 0); 44 45 } 46 47 }