一、數據結構java
編程的本質就是對數據(信息以數據的形式而存在)的處理,實際編程中不得不處理大量數據,所以實際動手編程以前必須先分析處理這些數據,處理數據之間存在的關係。node
現實的數據元素之間有個錯綜複雜的邏輯關係,須要採用合適的物理結構來存儲這些數據,並以此爲基礎對這些數據進行相應的操做。同時還要分析這些數據結構在時間和空間上的開銷。這種專門研究應用程序中的數據之間的邏輯關係,存儲方式及其操做的學問就是數據結構。git
數據元素之間存在的關聯關係被稱爲數據的邏輯結構,概括起來,大體有以下四種基本的邏輯結構:github
腦補圖:算法
圖片>代碼>文字,我的理解,能用圖片說明問題的就不要用代碼,同理,儘可能用代碼+文字解釋問題的本質。編程
同一種的邏輯結構,在底層一般有兩種物理存儲結構:數組
順序結構適合讀操做(爲啥呢?由於有索引啊),鏈表存儲適合寫操做(爲啥呢?斷開,加上節點就完成,不須要底層複製啊)網絡
算法的設計取決於邏輯結構:算法的實現依賴於存儲結構。對象的設計取決於類結構,(...)數據結構
什麼是數據結果呢?數據結構概括起來所要研究的問題就三方面:app
對象之間的關係(對現實的抽象,繼承?組合?),存儲在內存中哪裏,堆上啊,怎麼存?存在數組裏?hash表裏?怎麼處理的啊?增刪改查啊,排序那,加密解密啊,
對於普通的線性表而言,它的做用是一個容器,用於裝具備類似結果的數據。
如下圖片來自維基百科(百X百科就別看了)
原諒沒放恐怖的,來自Google(百X就別用了)
棧(Stack),是一種特殊的線性表,只能在固定的一端(線性表的尾端)進行插入、刪除操做。
容許進行插入、刪除操做的一端爲棧頂(top),另外一端,你猜?(bottom)
需求:
請編寫代碼實現Stack類,該類可以實現後進先出的堆棧功能,要求實現的方法包括:
-
萬惡的字符編碼,無比的鬱悶如下全部代碼參考網絡,在Sublime中編寫。
基於單列表實現:
class Node<E> { Node<E> next = null; E data; public Node(E data) { this.data = data; } } //採用單鏈表實現棧 public class MyStack<E> { int depth; //棧的深度 public MyStack(int i) { this.depth = i; } Node<E> top = null; //將元素壓入棧中 public boolean push(E data) { if(size() < depth) { Node<E> newNode = new Node<E>(data); newNode.next = top; top = newNode; return true; } return false; } //讀取棧中的頭節點,不刪除頭節點 public E peek() { if(top ==null) { return null; } return top.data; } //獲取棧中的頭節點,並刪除頭節點 public E pop() { if(top ==null) { return null; } Node<E> tmp = top; top = top.next; return tmp.data; } //棧的元素個數 public int size() { int len = 0; Node tmeNode = top; while(tmeNode != null) { tmeNode = tmeNode.next; len++; } return len; } //當前棧的深度 public int depth() { return this.depth; } public static void main(String[] args) { MyStack stack = new MyStack(2); System.out.println(stack.push(1)); System.out.println(stack.push(2)); System.out.println(stack.push(3)); System.out.println("棧的元素個數: " +stack.size()); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println("棧的元素個數: " + stack.depth()); } } ---------------------------此代碼來自《Java編程思想》---------------------------------- import java.util.LinkedList; public class Stack<T> { private LinkedList<T> storage = new LinkedList<T>(); public void push(T v) { storage.addFirst(v); } public T peek() { return storage.getFirst(); } public T pop() { return storage.removeFirst(); } public boolean empty() { return storage.isEmpty(); } public String toString() { return storage.toString(); } }
在來看看大佬的另外一種實現,簡單明瞭啊。
public class LinkedStack<T> { private static class Node<U> { U item; Node<U> next; Node() { item = null; next =null; } Node(U item,Node<U> next) { this.item = item; this.next = next; } boolean end() { return item == null && next == null; } } private Node<T> top = new Node<T>(); public void push(T item) { top = new Node<T>(item,top); } public T pop() { T result = top.item; if (!top.end()) { top = top.next; } return result; } public static void main(String[] args) { LinkedStack<String> lss = new LinkedStack<String>(); for (String s : "Phasers on stun!".split(" ") ) lss.push(s); String s; while((s = lss.pop()) != null) System.out.println(s); } } 輸出以下: I:\Java\note\sort\code>java LinkedStack stun! on Phasers
隊列(queue),也是一種特殊的線性表,使用固定的一端來插入數據,另外一端用於刪除數據
具體Queue實現:
import java.util.*; public class SimpleQueue<T> implements Iterable<T> { private LinkedList<T> storage = new LinkedList<T>(); public void add(T t){ storage.offer(t); } public T get() { return storage.poll(); } public Iterator<T> iterator() { return storage.iterator(); } public static void main(String[] args) { SimpleQueue queue = new SimpleQueue(); queue.add(8); System.out.println(queue.get()); } }
咱們在來看看用Stack如何實現Queue,很是不錯,《Java編程思想》
import java.util.Stack; public class MyQueue{ Stack<Integer> stack = new Stack<Integer>(); Stack<Integer> stackTmp = new Stack<Integer>(); //Push element X to the back of queue public void push(int x) { stack.push(x); } //Removes the element form in front of queue public void pop() { if (stackTmp.isEmpty()) { while (!stack.isEmpty()) { int tmp = stack.peek(); stackTmp.push(tmp); stack.pop(); } } else { stackTmp.pop(); } } //Get the front element public int peek() { if (!stackTmp.isEmpty()) { int tmp = stack.peek(); stackTmp.push(tmp); } return stackTmp.peek(); } //Return whether the queueis empty public boolean empty() { if (stackTmp.isEmpty() && stack.isEmpty()) { return true; }else { return false; } } public static void main(String[] args) { MyQueue queue = new MyQueue(); queue.push(8); System.out.println(queue.empty()); //false } }
樹,也是一種數據結構,非線性的,這種結構內的元素存在一對多的關係。
二叉樹,這裏採用遞歸和內部類的思想。
public class BinaryTree { private Node root; //添加節點 public void add(int data) { if (root ==null) { root = new Node(data); }else { root.addNode(data); } } //打印節點 public void print() { root.printNode(); } private class Node { private int data; private Node left; private Node right; public Node(int data) { this.data = data; } public void addNode(int data) { //核心思想就是進來先個當前節點比,若是若是小於則在左邊添加,若是左邊沒子節點,則建立,若是有添加 if (this.data > data) { if (this.left == null) { this.left = new Node(data); }else { this.addNode(data); //這裏應該是採用遞歸。 } }else { if (this.right == null) { this.right = new Node(data); }else { this.right.addNode(data); } } } //中序遍歷 public void printNode() { if (this.left != null) { this.left.printNode(); } System.out.println(this.data + "->"); if (this.right !=null) { this.right.printNode(); } } } } ------------------------測試----------------------------------------------- public static void main(String[] args) { BinaryTree bt = new BinaryTree(); // 八、三、十、一、六、1四、四、七、13 bt.add(8);bt.add(3);bt.add(10); bt.add(1);bt.add(6);bt.add(14); bt.add(4);bt.add(7);bt.add(13); bt.print(); } 輸出: 1->3->4->6->7->8->10->13->14->
ArrayList由於亂碼,寫了一半,無奈啊,徹底坑我,其思想就是根據索引,涉及到擴容,判斷越界了麼,。這裏先無論了。直接看LinkedList。
public class MyLinkedList { protected Node first; // 鏈表的第一個節點 protected Node last; // 鏈表的最後一個節點 private int size; // 節點的數量 // 鏈表中的每個節點 public class Node { public Node(Object ele) { this.ele = ele; } Node prev; // 上一個節點對象 Node next; // 下一個節點對象 public Object ele; // 當前節點中存儲的數據 } public void addFirst(Object ele) { Node node = new Node(ele); //須要保存的節點對象 //進來一個節點,若是爲空的話,它可定時第一個,也是最後一個 if (size == 0) { this.first = node; this.last = node; }else { node.next = this.first; // 把以前第一個做爲新增節點的下一個節點,(進來一個,當前的只能當老二了。) this.first.prev = node; // 把新增節點做爲以前第一個節點的上一個節點 this.first = node; // 把新增的節點做爲第一個節點 } size++; } //這裏很重要,別忘記 public void addLast(Object ele) { Node node = new Node(ele); if (size == 0) { this.first = node; this.last = node; }else { this.last.next = node; // 新增節點做爲以前最後一個節點的下一個節點(由於是加在後面,因此當前節點的下一個纔是 新增節點) node.prev = this.last; // 以前最後一個節點做爲新增節點的上一個節點 this.last = node; // 把新增的節點做爲最後一個節點 } } //原諒我複製了 public void remove(Object ele) { // 找到被刪除的節點 Node current = this.first;// 肯定爲第一個節點,從頭至尾開始找 for (int i = 0; i < size; i++) { if (!current.ele.equals(ele)) {// 當前爲true !true 爲false ,說明找到當前ele,輸出 if (current.next == null) { // 續上: 若是false取反爲true, 判斷是否最後一個, return; } current = current.next; } } //刪除節點 if(current==first){ this.first = current.next; //當前的下一個做爲第一個 this.first.prev = null; //當前下一個對上一個的引用設置爲null }else if(current==last){ this.last = current.prev; this.last.next = null; }else{ //把刪除當前節點的下一個節點做爲刪除節點的上一個節點的next current.prev.next =current.next; //把刪除節點的上一個節點做爲刪除節點下一個節點的prev current.next.prev = current.prev; } size--; //System.out.println("current =" + current.ele); } public String toString() { if (size == 0) { return "[]"; } StringBuilder sb = new StringBuilder(size * 2 + 1); Node current = this.first;// 第一個節點 sb.append("["); for (int i = 0; i < size; i++) { sb.append(current.ele); if (i != size - 1) { sb.append(","); } else { sb.append("]"); } current = current.next; // 獲取本身的下一個節點 } return sb.toString(); } }
這個雙向列表有點難理解,仍是看圖吧,
線性鏈表:
雙向鏈表:
先到這裏吧,gogogo,機會是留給有準備的人,