退役過久手生了唉..java
目前指望手撕的名單:
1.各類排序(歸併/快排/堆排/冒泡選擇插入/桶排/基數..)
2.各類數據結構(鏈表/堆/帶旋轉的平衡樹)
3.雜c++
主要是C++實現,有空我會接着改成Java(雖然沒差
實現方法儘可能是人盡皆知的那種
而且實現均會經過OJ測試
算法
1.歸併排序數據結構
void merge(int *arr, int lo, int mid, int hi) { int *tmp = (int *)malloc((hi-lo+1)*sizeof(int)); int i = lo, j = mid+1, k = 0; while(i<=mid && j<=hi) { if(arr[i] <= arr[j]) tmp[k++] = arr[i++]; else tmp[k++] = arr[j++]; } while(i <= mid) tmp[k++] = arr[i++]; while(j <= hi) tmp[k++] = arr[j++]; memcpy(arr+lo, tmp, k*sizeof(int)); free(tmp); } void mergeSort(int *arr, int lo, int hi) { if(lo == hi) return; int mid = lo+hi >> 1; mergeSort(arr, lo, mid); mergeSort(arr, mid+1, hi); merge(arr, lo, mid, hi); }
Java versiondom
package com.caturra.sorting; import java.util.*; /** * 歸併排序,我的習慣使用全閉區間,[lo,hi] * @author Caturra * */ public class MergeSort { public static void sort(Comparable[] comps,int lo,int hi) { if(lo >= hi) return; int mid = lo+hi >> 1; sort(comps,lo,mid); sort(comps,mid+1,hi); merge(comps,lo,mid,hi); } private static void merge(Comparable[] comps,int lo,int mid,int hi) { Comparable[] temp = new Comparable[hi-lo+1]; int i = lo, j = mid+1, k = 0; while(i <= mid && j <= hi) { int cmp = comps[i].compareTo(comps[j]); if(cmp < 0) { temp[k++] = comps[i++]; } else { temp[k++] = comps[j++]; } } while(i <= mid) temp[k++] = comps[i++]; while(j <= hi) temp[k++] = comps[j++]; for(k = lo; k <= hi; k++) comps[k] = temp[k-lo]; } /** * 測試樣例,HDU1425 * @param args */ public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNext()) { int n = sc.nextInt(); int m = sc.nextInt(); Integer[] arr = new Integer[n]; for(int i = 0; i < n; i++) { arr[i] = sc.nextInt(); } sort(arr, 0, n-1); for(int i = 0; i < n/2; i++) { arr[i] ^= arr[n-i-1]; arr[n-i-1] ^= arr[i]; arr[i] ^= arr[n-i-1]; } for(int i = 0; i < m-1; i++) System.out.print(arr[i]+" "); System.out.println(arr[m-1]); } } }
2.快排測試
快排幾乎沒敲過,過去太依賴sort了..
須要注意的點:
1.找軸點時i通過的地方必然保證小於將來的基準點,j同理必然大於將來的基準點,所以交錯時則中止掃描
\(comps[1...i-1] \lt p\) 交錯後\(j=i-1\),存在\(comps[0]>comps[j]\)的可能,所以還須要進一步交換知足軸點的定義
既交錯後\(comps[j] \geq comps[0...j-1]\)是最後一步保證的,\(comps[j] \lt comps[j+1...hi]\)是先前的雙指針交換保證的
2.j>=0是恆成立的,最後可能停留在0
3.有序表現很慘ui
Cpp實現參考自鄧俊輝老師的寫法,至關簡潔this
// trick:找軸點前先rand一下才能保證複雜度 int partition(int *arr, int lo,int hi) { swap(arr[lo], arr[lo+rand()%(hi-lo+1)]); int val = arr[lo], pivot = lo; for(int i = lo+1; i <= hi; i++) { if(arr[i] < val) swap(arr[++pivot], arr[i]); } swap(arr[lo], arr[pivot]); return pivot; } void quickSort(int *arr, int lo,int hi) { if(lo >= hi) return; int pivot = partition(arr, lo, hi); quickSort(arr, lo, pivot-1); quickSort(arr, pivot+1, hi); }
Java version編碼
package com.caturra.sorting; import java.util.Scanner; public class QuickSort { public static void sort(Comparable[] comps,int lo,int hi) { if(lo >= hi) return; int j = partition(comps,lo,hi); sort(comps,lo,j-1); sort(comps,j+1,hi); } private static int partition(Comparable[] comps,int lo,int hi) { exch(comps,lo,(int)(lo+Math.random()*(hi-lo))); //一般須要隨機化 Comparable val = comps[lo]; int i = lo, j = hi+1; while(true) { while(i < hi && comps[++i].compareTo(val) < 0); while(j > lo && comps[--j].compareTo(val) > 0); if(i >= j) break; exch(comps,i,j); } exch(comps,lo,j); return j; } private static void exch(Object[] comps,int i,int j) { Object t = comps[i]; comps[i] = comps[j]; comps[j] = t; } public static void main(String[] args) { // 測試同上 } }
爲了處理重複數過多帶來的劣化而引入三向切分的方法spa
public static void sort(Comparable[] comps,int lo,int hi) { if(lo >= hi) return; int lt = lo, gt = hi, i = lo+1; Comparable val = comps[lo]; while(i <= gt) { int cmp = comps[i].compareTo(val); if(cmp < 0) exch(comps,lt++,i++); //comps[i]過小,放入已經排好序的[0,lo)當中,此時和lt連續接壤 else if(cmp > 0) exch(comps,i,gt--); //放入大於val的一邊,引入的[gt]接着比較 else i++; } sort(comps,lo,lt-1); sort(comps,gt+1,hi); //此時[lt,gt]都是重複存在的數 }
3.\(O(n^2)\)排序俱樂部
// 至關直觀的寫法,有一種高逼格寫法學不來( void bubbleSort(int *arr, int lo, int hi) { bool isSorted = false; while(!isSorted) { isSorted = true; for(int i = lo; i < hi; i++) { if(arr[i] > arr[i+1]) { swap(arr[i], arr[i+1]); isSorted = false; } } } } /***************************************************/ //trick:倒過來交換是不斷挑選最優插入點的過程 void insertSort(int *arr, int lo, int hi) { for(int i = lo+1; i <= hi; i++) { int j = i; while(j>lo && arr[j]<arr[j-1]) { swap(arr[j], arr[j-1]); --j; } } } /***************************************************/ // 毫無實現難度 void selectSort(int *arr, int lo, int hi) { for(int i = lo; i <= hi; i++) { int minIdx = i; for(int j = i; j <= hi; j++) { if(arr[j] < arr[minIdx]) { minIdx = j; } } swap(arr[i], arr[minIdx]); } }
4.heap簡略版 / 沒有封裝堆排 / 沒有O(n)構造
struct Heap { int heap[MAXN],tot; void init(){ tot=0; } void insert(int val) { heap[++tot]=val; int now = tot; while(heap[now] < heap[now>>1]) { swap(heap[now],heap[now>>1]); now >>= 1; } } int pop() { int res = heap[1]; heap[1] = heap[tot--]; int now = 1; while(now*2 <= tot) { int nxt = now<<1; if(nxt+1<=tot && heap[nxt+1] < heap[nxt]) nxt++; // find min if(heap[now] < heap[nxt]) return res; swap(heap[now], heap[nxt]); now = nxt; } return res; } }h;
5.KMP
char text[MAXN], pattern[MAXN]; int f[MAXN], nxt[MAXN]; void init() { int len = strlen(pattern+1); int j = 0; nxt[1] = 0; for(int i = 2; i <= len; i++) { while(j>0 && pattern[i]!=pattern[j+1]) j = nxt[j]; if(pattern[i] == pattern[j+1]) j++; nxt[i] = j; } } int match() { int n = strlen(text+1), m = strlen(pattern+1); int j = 0, ans = 0; for(int i = 1; i <= n; i++) { while(j>0 && (j==m || text[i]!=pattern[j+1])) j = nxt[j]; if(text[i] == pattern[j+1]) j++; f[i] = j; if(f[i] == m) ans++; } return ans; }
6.Huffman編碼(醜
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e5+11; struct Node { int lc, rc; int weight; char val; int id; Node() {} Node(int _id,int _weight,char _val) { id = _id, weight = _weight, val = _val, lc = rc = 0; } bool operator < (const Node &rhs) const { return weight > rhs.weight; } }huffman[MAXN]; int tot; priority_queue<Node> pq; string ans[128]; string tmpBit; void dfs(int now) { if(huffman[now].val) { ans[huffman[now].val] = tmpBit; } tmpBit.push_back('0'); if(huffman[now].lc) dfs(huffman[now].lc); tmpBit.pop_back(); tmpBit.push_back('1'); if(huffman[now].rc) dfs(huffman[now].rc); tmpBit.pop_back(); } int num[128]; string str; int main() { while(cin >> str) { memset(num,0,sizeof num); tot = 0; while(!pq.empty()) pq.pop(); int all = 0, allId = 0; for(int i = 0; i < str.length(); i++) { if(num[str[i]] == 0) all++, allId = str[i]; num[str[i]]++; } if(all == 1) { cout << (char)allId <<":: " << 0 << endl; cout << "totLength: " << str.length() << endl; cout << "rate: " << str.length() << endl; continue; } for(int i = 1; i < 128; i++) { if(!num[i]) continue; huffman[++tot] = Node(tot,num[i],i); pq.push(huffman[tot]); } while(pq.size() > 1) { Node tmp1 = pq.top(); pq.pop(); Node tmp2 = pq.top(); pq.pop(); huffman[++tot] = Node(tot,tmp1.weight+tmp2.weight,0); huffman[tot].lc = tmp1.id; huffman[tot].rc = tmp2.id; pq.push(huffman[tot]); } for(int i = 0; i < 128; i++) ans[i].clear(); tmpBit.clear(); dfs(tot); long long totLen = 0; vector<char> characters; int uniqueLength = 0; for(int i = 0; i < 128; i++) { if(num[i]) { cout<<(char)i<<":: "<<ans[i]<<endl; characters.push_back(i); uniqueLength += ans[i].length(); } totLen += num[i] * ans[i].length(); } cout << "totLength: " << totLen << endl; cout << "rate: " << 8.0*str.length() / totLen << endl; int *encoded = (int *) malloc(((uniqueLength+31)/32)*sizeof(int)); memset(encoded,0,sizeof encoded); int nowLength = 0; for(int i = 0; i < characters.size(); i++) { for(int j = 0; j < ans[characters[i]].size(); j++) { int x = nowLength / 32; int y = nowLength % 32; int z = 0; if(ans[characters[i]][j] == '1') { z = 1; } encoded[x] |= (z<<y); nowLength++; } } cout<<"ordered table: "; for(int i = 0; i < characters.size(); i++) { cout<<(char)characters[i]<<" "; } cout<<endl; nowLength = 0; for(int i = 0; i < characters.size(); i++) { for(int j = 0; j < ans[characters[i]].size(); j++) { int x = nowLength / 32; int y = nowLength % 32; cout<<(encoded[x]>>y&1); nowLength++; } cout<<"|"; } cout<<endl; } return 0; }
堆(new version)
此次的堆實現是按照算法導論的思路寫的
import java.util.Arrays; import java.util.Scanner; // 默認大根堆 public class MyHeap { public int[] heap; public int size; public boolean heapStatus; public MyHeap(int capacity) { heap = new int[capacity]; size = 0; } public int down(int size,int idx) { int mx = 0; int res = heap[idx]; while(mx != idx) { mx = idx; int lc = idx << 1; int rc = idx << 1 |1; if(lc <= size && heap[lc] > heap[idx]) { mx = lc; } if(rc <= size && heap[rc] > heap[mx]) { mx = rc; } if(mx != idx) { res = Math.max(res,heap[mx]); swap(heap,mx,idx); idx = mx; // idx換成了mx 但val仍是原來下沉的那個 mx = 0; } } return res; } public void build(int[] arr) { for(int i = 1; i <= arr.length; i++) { heap[i] = arr[i-1]; } size = arr.length; for(int i = size>>1; i >= 1; --i) { down(size,i); } heapStatus = true; } public void swap(int[] arr,int i,int j) { int t = arr[i]; arr[i] = arr[j]; arr[j] = t; } public void heapSort(int[] arr) { build(arr); for(int i = size; i >= 2; --i) { swap(heap,1,i); down(i-1,1); } } public void up(int i) { while(i > 1 && heap[i] > heap[i>>1]) { swap(heap,i,i>>1); i >>= 1; } } public void insert(int val) { heap[++size] = val; up(size); } public int remove() { int res = down(size,1); swap(heap,1,size--); down(size,1); return res; } public static void main(String[ ] args) { MyHeap heap = new MyHeap(222); int[] arr = new int[] {0,5,2,67,4,1,6,9,3,2,11,7,0}; heap.build(arr); System.out.println(Arrays.toString(heap.heap)); System.out.println("built"); heap.insert(5); heap.insert(666); heap.insert(-1); heap.remove(); System.out.println("rm:"+heap.remove()); // System.out.println("rm:"+heap.remove()); // heap.heapSort(arr); System.out.println(Arrays.toString(heap.heap)); } }
LCA-RMQ實現
import java.util.HashMap; class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } class Solution { public HashMap<TreeNode,Integer> dep = new HashMap<>(); public HashMap<TreeNode,TreeNode>[] p = new HashMap[20]; public void dfs(TreeNode rt,TreeNode fa) { if(fa == null) { dep.put(rt,0); p[0].put(rt,rt); } else { dep.put(rt,dep.get(fa)+1); p[0].put(rt,fa); } for(int i = 1; i < 20; i++) { p[i].put(rt,p[i-1].get(p[i-1].get(rt))); } if(rt.left != null) dfs(rt.left,rt); if(rt.right != null) dfs(rt.right,rt); } TreeNode lca(TreeNode u,TreeNode v) { if(dep.get(u) < dep.get(v)) { TreeNode t = u; u = v; v = t; } for(int i = 0; i < 20; i++) { if((dep.get(u)-dep.get(v) >>i&1) == 1) { u = p[i].get(u); } } if(u == v) return u; for(int i = 19; i >= 0; --i) { if(p[i].get(u) != p[i].get(v)) { u = p[i].get(u); v = p[i].get(v); } } return p[0].get(u); } public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if(root == null || p == null || q == null) return null; for(int i = 0; i < 20; i++) this.p[i] = new HashMap<>(); dfs(root,null); return lca(p,q); } }