數據結構java
一、鏈表node
由不定數量的節點(Node)組成,每一個節點僅知道下一個結點的位置,且向外僅僅暴露頭(head),一切操做直接或者間接從頭開始;算法
代碼:單向鏈表的實現、鏈表反轉、鏈表中間點查詢、鏈表排序shell
1.1單向鏈表的實現數組
1 // 鏈表的實現 2 public class Test { 3 public static void main(String[] args) { 4 NodeManager nodeManager = new NodeManager(); 5 nodeManager.addNode("大"); 6 nodeManager.addNode("家"); 7 nodeManager.addNode("好"); 8 nodeManager.addNode("才"); 9 nodeManager.addNode("是"); 10 nodeManager.addNode("真"); 11 nodeManager.addNode("的"); 12 nodeManager.delNode("好"); 13 nodeManager.print(); 14 } 15 } 16 //節點管理類--封裝的增刪改 17 class NodeManager { 18 19 private Node root;//根節點 20 21 //添加節點 22 public void addNode(String data) { 23 if (root == null) { 24 root = new Node(data); 25 } else { 26 root.addNode(data); 27 } 28 } 29 //刪除節點 30 public void delNode (String data) { 31 if (root.data.equals(data)){ 32 root = root.next; 33 } else { 34 root.delNode(data); 35 } 36 } 37 //打印節點 38 public void print() { 39 if (root != null) { 40 System.out.print(root.data + " ->"); 41 root.print(); 42 } 43 } 44 45 46 47 // 節點類--節點結構和自帶簡易方法 48 class Node { 49 private String data;//數據源 50 private Node next;//指針域 51 52 public Node(String data) { 53 this.data = data; 54 } 55 //添加方法 56 public void addNode(String data) { 57 if (this.next == null) { 58 this.next = new Node(data); 59 } else { 60 this.next.addNode(data); 61 } 62 } 63 //刪除方法 64 public void delNode(String name) { 65 if (this.next != null) { 66 if (this.next.data.equals(name)) { 67 this.next = this.next.next; 68 } else { 69 this.next.delNode(name); 70 } 71 } 72 } 73 //打印方法 74 public void print() { 75 if (this.next != null) { 76 System.out.print(this.next.data + "->"); 77 this.next.print(); 78 } 79 } 80 } 81 }
1.2鏈表反轉數據結構
1 /** 2 * 鏈表反轉 3 * 4 * @param head 5 * @return 6 */ 7 public Node ReverseIteratively(Node head) { 8 Node pReversedHead = head; 9 Node pNode = head; 10 Node pPrev = null; 11 while (pNode != null) { 12 Node pNext = pNode.next; 13 if (pNext == null) { 14 pReversedHead = pNode; 15 } 16 pNode.next = pPrev; 17 pPrev = pNode; 18 pNode = pNext; 19 } 20 this.head = pReversedHead; 21 return this.head; 22 }
1.3鏈表中間點查詢post
1 /** 2 * 查找單鏈表的中間節點 3 * 採用快慢指針的方式查找單鏈表的中間節點,快指針一次走兩步,慢指針一次走一步,當快指針走完時,慢指針恰好到達中間節點 4 * @param head 5 * @return 6 */ 7 public Node SearchMid(Node head) { 8 Node p = this.head, q = this.head; 9 while (p != null && p.next != null && p.next.next != null) { 10 p = p.next.next; 11 q = q.next; 12 } 13 System.out.println("Mid:" + q.data); 14 return q; 15 }
1.4鏈表排序大數據
1 /** 2 * 排序 3 * 用當前的node和隨後的全部的比較並進行位置互換,一波後挪一個節點 4 * @return 5 */ 6 public Node orderList() { 7 Node nextNode = null; 8 int tmp = 0; 9 Node curNode = head; 10 while (curNode.next != null) { 11 nextNode = curNode.next; 12 while (nextNode != null) { 13 if (curNode.data > nextNode.data) { 14 tmp = curNode.data; 15 curNode.data = nextNode.data; 16 nextNode.data = tmp; 17 } 18 nextNode = nextNode.next; 19 } 20 curNode = curNode.next; 21 } 22 return head; 23 }
二、隊列與棧ui
棧:數據只能在棧的一端即棧頂位置進行插入和刪除操做;先進後出,後進先出this
隊列:數據只能在隊列的一端插入並在另外一端進行刪除操做;先進先出
代碼:棧的實現、隊列的實現
2.1棧的實現
1 //棧的實現push和pop 2 public void push(T data) { 3 if (data==null){ 4 throw new StackException("data can't be null"); 5 } 6 if(this.top==null){ 7 //調用pop()後top可能爲null 8 this.top=new Node<T>(data); 9 }else if(this.top.data==null){ 10 this.top.data=data; 11 }else { 12 Node<T> p=new Node<T>(data,this.top); 13 top=p; 14 //更新棧頂 15 } 16 size++; 17 } 18 public T pop() { 19 if(isEmpty()){ 20 throw new EmptyStackException("Stack empty"); 21 } 22 23 T data=top.data; 24 top=top.next; 25 size--; 26 return data; 27 }
2.2隊列實現
1 /** 2 * 隊列入隊算法 3 * @param data 4 * @author WWX 5 */ 6 public void enqueue(T data){ 7 //建立一個節點 8 Node s=new Node(data,null); 9 //將隊尾指針指向新加入的節點,將s節點插入隊尾 10 rear.next=s; 11 rear=s; 12 size++; 13 } 14 15 /** 16 * 隊列出隊算法 17 * @return 18 * @author WWX 19 */ 20 public T dequeue(){ 21 if(rear==front){ 22 try { 23 throw new Exception("堆棧爲空"); 24 } catch (Exception e) { 25 e.printStackTrace(); 26 } 27 return null; 28 }else{ 29 //暫存隊頭元素 30 Node p=front.next; 31 T x=p.data; 32 //將隊頭元素所在節點摘鏈 33 front.next=p.next; 34 //判斷出隊列長度是否爲1 35 if(p.next==null) 36 rear=front; 37 //刪除節點 38 p=null; 39 size--; 40 return x; 41 } 42 }
三、二叉樹
二叉樹:N個結點構成的有限集合;每一個結點至多隻有兩棵子樹(即二叉樹中不存在度大於2的結點),而且,二叉樹的子樹有左右之分,其次序不能任意顛倒。
特性: (1)若根結點的層次爲1,則二叉樹第i層最多有2i−1(i≥1)個結點;在高度爲h的二叉樹中,最多有2h−1個結點(h≥0);
(2)滿二叉樹和徹底二叉樹
(3) 一棵具備n個結點的徹底二叉樹,對於序號爲i(0≤i<n)的結點,則有以下規則
①若i=0,則i爲根結點,無父母結點;若i>0,則i的父母結點序號爲⌊i−12⌋(向下取整)。
②若2i+1<n,則i的左孩子結點序號爲2i+1,不然i無左孩子。
③若2i+2>n,則i的右孩子結點序號爲2i+2,不然i無右孩子。
代碼:二叉樹實現、遍歷
3.1二叉樹實現
1 // 二叉樹數據結構的實現 2 public class Test { 3 public static void main(String[] args) { 4 BinaryTreeManger binaryTreeManger = new BinaryTreeManger(); 5 6 binaryTreeManger.add(1); 7 binaryTreeManger.add(3); 8 binaryTreeManger.add(4); 9 binaryTreeManger.add(8); 10 binaryTreeManger.add(6); 11 binaryTreeManger.print(); 12 } 13 } 14 15 class BinaryTreeManger{ 16 17 private Node root;//根節點 18 19 public void add(int data) { 20 if (root == null) { 21 root = new Node(data); 22 } else { 23 root.addNode(data); 24 } 25 } 26 public void print() { 27 root.print(); 28 } 29 class Node{ 30 private int data; 31 private Node left; //左子樹 32 private Node right; //右子樹 33 34 public Node(int data) { 35 this.data = data; 36 } 37 //添加節點 38 public void addNode(int data) { 39 //首先判斷大小,來決定將data放在那個子樹上 40 if (data > this.data){//當前數據較大,放在右子樹 41 if (this.right == null) { 42 this.right = new Node(data); 43 } else { 44 this.right.addNode(data); 45 } 46 } else { //較小放在左子樹上 47 if (this.left == null) { 48 this.left = new Node(data); 49 } else { 50 this.left.addNode(data); 51 } 52 53 } 54 55 } 56 //中序遍歷 左 -> 根 -> 右 57 public void print() { 58 if (this.left != null) { 59 this.left.print(); 60 } 61 System.out.print(data); 62 if (this.right != null) { 63 this.right.print(); 64 } 65 } 66 } 67 }
3.2二叉樹遍歷
1 public void visted(TreeNode subTree){ 2 subTree.isVisted=true; 3 System.out.println("key:"+subTree.key+"--name:"+subTree.data);; 4 } 5 //前序遍歷 6 public void preOrder(TreeNode subTree){ 7 if(subTree!=null){ 8 visted(subTree); 9 preOrder(subTree.leftChild); 10 preOrder(subTree.rightChild); 11 } 12 } 13 14 //中序遍歷 15 public void inOrder(TreeNode subTree){ 16 if(subTree!=null){ 17 inOrder(subTree.leftChild); 18 visted(subTree); 19 inOrder(subTree.rightChild); 20 } 21 } 22 23 //後續遍歷 24 public void postOrder(TreeNode subTree) { 25 if (subTree != null) { 26 postOrder(subTree.leftChild); 27 postOrder(subTree.rightChild); 28 visted(subTree); 29 } 30 } 31 32 //前序遍歷的非遞歸實現 33 public void nonRecPreOrder(TreeNode p){ 34 Stack<TreeNode> stack=new Stack<TreeNode>(); 35 TreeNode node=p; 36 while(node!=null||stack.size()>0){ 37 while(node!=null){ 38 visted(node); 39 stack.push(node); 40 node=node.leftChild; 41 } 42 while(stack.size()>0){ 43 node=stack.pop(); 44 node=node.rightChild; 45 } 46 } 47 } 48 49 //中序遍歷的非遞歸實現 50 public void nonRecInOrder(TreeNode p){ 51 Stack<TreeNode> stack =new Stack<BinaryTree.TreeNode>(); 52 TreeNode node =p; 53 while(node!=null||stack.size()>0){ 54 //存在左子樹 55 while(node!=null){ 56 stack.push(node); 57 node=node.leftChild; 58 } 59 //棧非空 60 if(stack.size()>0){ 61 node=stack.pop(); 62 visted(node); 63 node=node.rightChild; 64 } 65 } 66 } 67 68 //後序遍歷的非遞歸實現 69 public void noRecPostOrder(TreeNode p){ 70 Stack<TreeNode> stack=new Stack<BinaryTree.TreeNode>(); 71 TreeNode node =p; 72 while(p!=null){ 73 //左子樹入棧 74 for(;p.leftChild!=null;p=p.leftChild){ 75 stack.push(p); 76 } 77 //當前結點無右子樹或右子樹已經輸出 78 while(p!=null&&(p.rightChild==null||p.rightChild==node)){ 79 visted(p); 80 //紀錄上一個已輸出結點 81 node =p; 82 if(stack.empty()) 83 return; 84 p=stack.pop(); 85 } 86 //處理右子樹 87 stack.push(p); 88 p=p.rightChild; 89 } 90 }
借鑑博客(版權已被聲明):http://blog.csdn.net/javazejian/article/details/53727333
四、其餘
串:若干個字符組成的有限序列;
數組:有限個類型相同的變量的集合;
廣義表:若干個元素組成的有限序列;
排序算法
各類排序算法時間複雜度和空間複雜度
一、插入排序
插入排序:穩定,最好最壞均爲O(n2);
原理:拿要後邊要排序元素與前邊已經排好的元素進行比較,從後向前掃描,找到位置並插入;
shell排序:不穩定,平均O(n1.5),最壞O(n2);
原理:數據等距離分組,組內插入排序;分組距離減半,組內繼續插入排序....
1.1插入排序
1 for (int i = 0; i < len; i++) { 2 for (int j = i + 1; j < len && j > 0; j--) { 3 if (a[j] < a[j - 1]) { 4 int temp = a[j]; 5 a[j] = a[j - 1]; 6 a[j - 1] = temp; 7 } 8 } 9 }
1.2shell排序
1 int group, i, j, temp,len; 2 len = unsorted.length; 3 for (group = len / 2; group > 0; group /= 2) 4 { 5 for (i = group; i < len; i++) 6 { 7 for (j = i - group; j >= 0; j -= group) 8 { 9 if (unsorted[j] > unsorted[j + group]) 10 { 11 temp = unsorted[j]; 12 unsorted[j] = unsorted[j + group]; 13 unsorted[j + group] = temp; 14 } 15 } 16 } 17 }
二、選擇排序
直接選擇:不穩定,最好最壞均爲O(n2);
原理:每次從當前位置到最末尾,獲取最小數據互換到當前位置,並依次後移
堆排序:不穩定,最好最壞均爲O(nlog2n);
原理:徹底二叉樹,大頂堆(父節點大於等於子節點),小頂堆(父節點小於等於子節點);
數據構建徹底二叉樹->大頂堆->根節點換到葉子節點左右側(把最大數據放到最後)->大頂堆->根節點換到葉子節點左右側(再次把第二大數據放到最後第二位置)....
2.1直接選擇
1 //min 記錄最小數據,index記錄最小位置 2 int min = 0; 3 int index = 0; 4 int len = a.length; 5 for (int i = 0; i < len - 1; i++) { 6 min = a[i]; 7 index = i; 8 for (int j = i + 1; j < len; j++) { 9 if (a[j] < min) { 10 min = a[j]; 11 index = j; 12 } 13 } 14 a[index] = a[i]; 15 a[i] = min; 16 }
2.2堆排序
1 //調整堆 2 void HeapAdjust(int *a,int i,int size) 3 { 4 int lchild=2*i; //i的左孩子節點序號 5 int rchild=2*i+1; //i的右孩子節點序號 6 int max=i; //臨時變量 7 if(i<=size/2) //若是i是葉節點就不用進行調整 8 { 9 if(lchild<=size&&a[lchild]>a[max]) 10 { 11 max=lchild; 12 } 13 if(rchild<=size&&a[rchild]>a[max]) 14 { 15 max=rchild; 16 } 17 if(max!=i) 18 { 19 swap(a[i],a[max]); 20 HeapAdjust(a,max,size); //避免調整以後以max爲父節點的子樹不是堆 21 } 22 } 23 } 24 void BuildHeap(int *a,int size) //創建堆 25 { 26 int i; 27 for(i=size/2;i>=1;i--) //非葉節點最大序號值爲size/2 28 { 29 HeapAdjust(a,i,size); 30 } 31 } 32 void HeapSort(int *a,int size) //堆排序 33 { 34 int i; 35 BuildHeap(a,size); 36 for(i=size;i>=1;i--) 37 { 38 swap(a[1],a[i]); //交換堆頂和最後一個元素,即每次將剩餘元素中的最大者放到最後面 39 HeapAdjust(a,1,i-1); //從新調整堆頂節點成爲大頂堆 40 } 41 }
三、交換排序
冒泡排序:穩定,平均最壞均爲O(n2);
原理:重複走訪數據,每加入一次數據,從該位置起,相鄰數據兩兩比較,位置互換;
快速排序:不穩定,平均爲O(nlog2n),最壞爲O(n2);
原理:將數據分隔成兩部分,左邊<key<右邊,依次遞歸,縮小範圍
3.1冒泡排序
1 //j與j+1相鄰比較 2 for(int i = 0; i < len-1; i++){ 3 for (int j = 0; j > len-i; j++){ 4 if (array[j] < array[j+1] ){ 5 swap(array,j,j+1); 6 } 7 } 8 }
3.2快速排序
1 public void sort(int[] a,int low,int high){ 2 int start = low; 3 int end = high; 4 int key = a[low]; 5 6 7 while(end>start){ 8 //從後往前比較 9 //若是沒有比關鍵值小的,比較下一個,直到有比關鍵值小的交換位置,而後又從前日後比較 10 while(end>start&&a[end]>=key) 11 end--; 12 if(a[end]<=key){ 13 int temp = a[end]; 14 a[end] = a[start]; 15 a[start] = temp; 16 } 17 //從前日後比較 18 //若是沒有比關鍵值大的,比較下一個,直到有比關鍵值大的交換位置 19 while(end>start&&a[start]<=key) 20 start++; 21 if(a[start]>=key){ 22 int temp = a[start]; 23 a[start] = a[end]; 24 a[end] = temp; 25 } 26 //此時第一次循環比較結束,關鍵值的位置已經肯定了。 27 //左邊的值都比關鍵值小,右邊的值都比關鍵值大, 28 //可是兩邊的順序還有多是不同的,進行下面的遞歸調用 29 } 30 //遞歸 31 if(start>low) sort(a,low,start-1);//左邊序列。第一個索引位置到關鍵值索引-1 32 if(end<high) sort(a,end+1,high);//右邊序列。從關鍵值索引+1到最後一個 33 }
四、歸併排序
五、基數排序
平均O(n3/2),最壞O(n2)