退役太久手生了唉..
目前期望手撕的名單: 1.各種排序(歸並/快排/堆排/冒泡選擇插入/桶排/基數..) 2.各種數據結構(鏈表/堆/帶旋轉的平衡樹) 3.雜
主要是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 version
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.有序表現很慘
Cpp實現參考自鄧俊輝老師的寫法,相當簡潔
// 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) {
// 測試同上
}
}
為了處理重復數過多帶來的劣化而引入三向切分的方法
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);
}
}