0%

HDU 1164

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <bits/stdc++.h>
#define DBG(x) cerr << #x << " = " << x << endl

using namespace std;
typedef long long LL;

const int MAXN = 65535 + 16;
bool is_prime[MAXN];
vector<int> primes;

struct Factor {
int value;
int cnt;

Factor() {}

Factor(int value, int cnt) : value(value), cnt(cnt) {}
};

void init_prime() {
fill(is_prime, is_prime + MAXN, true);
is_prime[0] = is_prime[1] = false;
for (int i = 2; i < MAXN; i++) {
if (!is_prime[i]) continue;
primes.push_back(i);
for (long long j = 1LL * i * i; j < MAXN; j += i) {
is_prime[j] = false;
}
}
}

vector<Factor> get_factors(int x) {
vector<Factor> factors;
int temp = x;
for (int i = 0; i < primes.size() && primes[i] <= x / primes[i]; i++) {
if (temp % primes[i] == 0) {
Factor factor(primes[i], 0);
while (temp % primes[i] == 0) {
factor.cnt++;
temp /= primes[i];
}
factors.push_back(factor);
}
}

if (temp > 1) {
factors.push_back(Factor(temp, 1));
}

return factors;
}

int main(int argc, char **argv) {
init_prime();
int x;
while (scanf("%d", &x) != EOF) {
vector<Factor> factors = get_factors(x);
string ans;
for (int i = 0; i < factors.size(); i++) {
for (int j = 0; j < factors[i].cnt; j++) {
if (!ans.empty()) ans += '*';
ans += to_string(factors[i].value);
}
}
puts(ans.c_str());
}
return 0;
}

HDU 4548

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <bits/stdc++.h>
#define DBG(x) cerr << #x << " = " << x << endl

using namespace std;
typedef long long LL;

const int MAXN = 1000000 + 16;

struct Prime {
bool is_prime[MAXN];
int sum[MAXN];

Prime() {
fill(is_prime, is_prime + MAXN, true);
fill(sum, sum + MAXN, 0);
is_prime[0] = is_prime[1] = false;
for (int i = 2; i < MAXN; i++) {
if (!is_prime[i]) continue;
for (long long j = 1LL * i * i; j < MAXN; j += i) {
is_prime[j] = false;
}
}
for (int i = 1; i < MAXN; i++) {
sum[i] = sum[i - 1];
if (is_beautiful(i)) sum[i]++;
}
}

bool is_beautiful(int x) {
if (!is_prime[x]) return false;
int s = 0;
while (x) {
s += x % 10;
x /= 10;
}
return is_prime[s];
}

int get(int l, int r) {
return sum[r] - sum[l - 1];
}
} p;

int main(int argc, char **argv) {
int T;
scanf("%d", &T);
for (int cas = 1; cas <= T; cas++) {
int l, r;
scanf("%d%d", &l, &r);
printf("Case #%d: %d\n", cas, p.get(l, r));
}
return 0;
}

Implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <bits/stdc++.h>
#define DBG(x) cerr << #x << " = " << x << endl

using namespace std;
typedef long long LL;

void qsort(vector<int> &vec, int s, int e) {
if (s >= e) return;
int pv = vec[s];
int l = s, r = e;
for (int i = s + 1, left = e - s; left > 0; left--) {
if (vec[i] < pv) {
vec[l++] = vec[i++];
} else {
swap(vec[i], vec[r--]);
}
}
assert(l == r);
vec[l] = pv;
qsort(vec, s, l - 1);
qsort(vec, l + 1, e);
}

int main(int argc, char **argv) {
srand(time(NULL));
vector<int> vec(500000);
for (int i = 0; i < vec.size(); i++) vec[i] = random();
vector<int> s = vec;

sort(s.begin(), s.end());
qsort(vec, 0, vec.size() - 1);

assert(s == vec);

return 0;
}

Golang version updated at 2020-04-20

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

type less []int

func (l less) Less(i, j int) bool {
return l[i] < l[j]
}

func (l less) Swap(i, j int) {
l[i], l[j] = l[j], l[i]
}

func (l less) Len() int {
return len(l)
}

func quickSort(data less, s, e int) {
if s >= e {
return
}

data.Swap(s, rand.Int()%(e-s+1)+s)

l, r := s, e
for i, left := s+1, e-s; left > 0; left-- {
if data.Less(i, l) {
data.Swap(i, l)
i++
l++
} else {
data.Swap(i, r)
r--
}
}
quickSort(data, s, l-1)
quickSort(data, l+1, e)
}

func sortArray(nums []int) []int {
rand.Seed(time.Now().Unix())
data := less(nums)
quickSort(data, 0, data.Len()-1)
return nums
}

Proof

Correctness of partition

\(s\) is the first index in the subarray of \(vec\), \(e\) is the last index in the subarray of \(vec\). \(vec[s:e]\) denotes the whole subarray, inclusive. At the start of the for loop:

  • \(i\) denotes the index of the element to be compared with the pivot
  • \(left\) denotes the number of remaining elements to be compared
  • \(l\) denotes the minimum position to put the element which is smaller than the pivot
  • \(r\) denotes the maximum position to put the element which is greater than or equal to the pivot

We say there are \(x\) elements \(<\) pivot, then there are supposed to be \(e - s - x\) elements \(>=\) pivot. After the for loop terminates, \(l\) will be \(s + x\), and \(y\) will be \(e - (e - s - x) = s + x\) too, so \(l = r\). The elements on the left side of \(l \ or\ r\) are all \(<\) pivot, and the elements of the right side of \(l \ or \ r\) are all \(>=\) pivot, then we put the pivot on the position \(l \ or \ r\). Then all the elements on the left side of the pivot will be smaller than the pivot, and all the elements on the right side of the pivot will be greater than or equal to the pivot. Thus, the partition is correct.

Correctness of recursion

Proof by induction. Suppose that \(P(n)\) is a predicate defined on \(n \in [1, \infty)\) meaning the \(Quick Sort\) is correct on a given array sized \(n\). If we can show that: 1. \(P(1)\) is true 2. (\(\forall k < n \ P(k)) \implies P(n)\)

Then \(P(n)\) is true for all integers \(n >= 1\). \(P(1)\) is obviously true.

To use quicksort to sort an array of size 𝑛, we partition it into three pieces: the first 𝑘 subarray, the pivot (which will be in its correct place), and the remaining subarray of size 𝑛−𝑘−1. By the way partition works, every element in the first subarray will be less than or equal to the pivot and every element in the other subarray will be greater than or equal to the pivot, so when we recursively sort the first and last subarrays, we will wind up having sorted the entire array.

We show this is correct by strong induction: since the first subarray has 𝑘<𝑛 elements, we can assume by induction that it will be correctly sorted. Since the second subarray has 𝑛−𝑘−1<𝑛 elements, we can assume that it will be correctly sorted. Thus, putting all the pieces together, we will wind up having sorted the array.1


  1. https://cs.stackexchange.com/a/63667↩ī¸Ž

Stars

Two dimensional binary indexed tree.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <bits/stdc++.h>
#define DBG(x) cerr << #x << " = " << x << endl

using namespace std;
typedef long long LL;

const int N = 1002;

struct Bit {
int c[N][N];
int n, m;

static int lowbit(int x) {
return x & -x;
}

void init(int n, int m) {
this->n = n;
this->m = m;
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= m; j++) {
c[i][j] = 0;
}
}
}

void add(int x, int y, int v) {
for (int i = x; i <= n; i += lowbit(i)) {
for (int j = y; j <= m; j += lowbit(j)) {
c[i][j] += v;
}
}
}

int get(int x, int y) {
int s = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
for (int j = y; j > 0; j -= lowbit(j)) {
s += c[i][j];
}
}
return s;
}
} bit;

bool star[N][N];

int main(int argc, char **argv) {
int n;
while (scanf("%d", &n) != EOF) {
int m = 1001;
bit.init(m, m);
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= m; j++) {
star[i][j] = false;
}
}
for (int i = 0; i < n; i++) {
char op[2];
scanf("%s", op);
if (op[0] == 'B') {
int x, y;
scanf("%d%d", &x, &y);
x++, y++;
if (!star[x][y]) {
star[x][y] = true;
bit.add(x, y, 1);
}
} else if (op[0] == 'D') {
int x, y;
scanf("%d%d", &x, &y);
x++, y++;
if (star[x][y]) {
star[x][y] = false;
bit.add(x, y, -1);
}
} else {
int x1, x2, y1, y2;
scanf("%d%d%d%d", &x1, &x2, &y1, &y2);
if (x1 > x2) {
swap(x1, x2);
}
if (y1 > y2) {
swap(y1, y2);
}
x1++, x2++, y1++, y2++;
int res = bit.get(x2, y2) - bit.get(x1 - 1, y2) - bit.get(x2, y1 - 1) + bit.get(x1 - 1, y1 - 1);
printf("%d\n", res);
}
}
}
return 0;
}

236. Lowest Common Ancestor of a Binary Tree

If we can find two subtrees of root such that both of them has target, then root is the LCA of p and q. If there is exactly one subtree of root having target and root itself has target, then root is the LCA of p and q too.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode *ans;
bool hasTarget(TreeNode *root, TreeNode *p, TreeNode *q) {
if (root == nullptr) return false;

bool left = hasTarget(root->left, p, q);
bool right = hasTarget(root->right, p, q);
bool mid = root == p || root == q;

if ((left && right) || (left && mid) || (mid && right)) {
ans = root;
}

return left || right || mid;
}

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
ans = nullptr;
hasTarget(root, p, q);
return ans;
}
};

Unique Binary Search Trees

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int numTrees(int n) {
// We consider the position of node n in the tree first.
// Because all nodes on the tree except for node n is less than node,
// if node n has children, that must be its left child.
// Node n can have a parent if the value of its parent is less than its.
// So we separate the n - 1 nodes into 2 parts, the first part is considered to be the parent part of node n,
// and the second part is considered to be the left child part of node n.
// We traverse every possible separation, for each separation we add the multiplication of the number of the combination
// of the two parts to the answer of node n.
vector<int> dp(n + 1, 0);
dp[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < i; j++) {
dp[i] += dp[j] * dp[i - 1 - j];
}
}
return dp[n];
}
};

33. Search in Rotated Sorted Array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0, r = nums.size() - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) return mid;
if (nums[mid] < target) {
// target on the left side and mid on the right side
if (target > nums[r] && nums[mid] < nums[l]) r = mid - 1;
else l = mid + 1;
} else {
// target on the right side and mid on the left side
if (target < nums[l] && nums[mid] > nums[r]) l = mid + 1;
else r = mid - 1;
}
}
return -1;
}
};

Implementation

Some details of this implementation borrow from sonyflake. Here using 8 bits to represent time in units of 500ms, 4 bits to represent sequence, 4 bits to represent machine. As a result:

  • The lifetime is \(2^8 \times 500ms = 128s\)
  • It can work in \(2^4 = 16\) distributed machines
  • It can generate \(2^4 = 16\) IDs per \(500ms\) at most in a single thread

Code

server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package main

import (
"errors"
"net/http"
"os"
"sync"
"time"

"github.com/gin-gonic/gin"
logger "github.com/sirupsen/logrus"
"github.com/x-cray/logrus-prefixed-formatter"
)

func init() {
logger.SetFormatter(&prefixed.TextFormatter{
TimestampFormat: "2006-01-02 15:04:05",
FullTimestamp: true,
ForceFormatting: true,
DisableColors: true,
})
logger.SetOutput(os.Stdout)
logger.SetLevel(logger.DebugLevel)
}

const (
BitLenTick = 8
BitLenSequence = 4
BitLenMachineID = 4

tickTimeUnit = time.Millisecond * 500
)

var idFlake *IDFlake

type IDFlake struct {
mu sync.Mutex

machineID int64
startTick int64 // ticks of the start time of IDFlake from UNIX epoch
elapsedTick int64 // elapsed ticks from start tick
sequence int64
}

func toFlakeTime(t time.Time) int64 {
return t.UTC().UnixNano() / int64(tickTimeUnit)
}

func NewIDFlake(machineID int64, startTime time.Time) *IDFlake {
return &IDFlake{
machineID: machineID,
startTick: toFlakeTime(startTime),
elapsedTick: 0,
sequence: 0,
}
}

func (f *IDFlake) toID() (uint64, error) {
if f.elapsedTick >= 1<<BitLenTick {
return 0, errors.New("over the time limit")
}

return uint64(f.elapsedTick<<(BitLenMachineID+BitLenSequence)) | uint64(f.machineID<<BitLenSequence) | uint64(f.sequence), nil
}

func (f *IDFlake) getID() (uint64, error) {
f.mu.Lock()
defer f.mu.Unlock()

currentTick := toFlakeTime(time.Now()) - f.startTick
if f.elapsedTick < currentTick {
f.sequence = 0
f.elapsedTick = currentTick
} else {
f.sequence = (f.sequence + 1) & (1<<BitLenSequence - 1)
if f.sequence == 0 {
f.elapsedTick++
sleepFor := sleepTime(f.elapsedTick - currentTick)
time.Sleep(sleepFor)
logger.Infof("slept for %.8fms", sleepFor.Seconds()*1000)
}
}

return f.toID()
}

func sleepTime(overTick int64) time.Duration {
return time.Duration(overTick)*tickTimeUnit - time.Duration(time.Now().UTC().UnixNano())%tickTimeUnit
}

func Decompose(id uint64) map[string]uint64 {
return map[string]uint64{
"id": id,
"tick": id >> (BitLenMachineID + BitLenSequence),
"machine": (id >> BitLenSequence) & (1<<BitLenMachineID - 1),
"sequence": id & (1<<BitLenSequence - 1),
}
}

func getID(c *gin.Context) {
id, err := idFlake.getID()
if err != nil {
logger.Warnf("getID error: %v", err)
c.JSON(http.StatusOK,
map[string]interface{}{
"error": err.Error(),
},
)
return
}
result := Decompose(id)
c.JSON(http.StatusOK, result)
}

func httpRun() {
r := gin.Default()
r.GET("/get_id", getID)
r.Run(":8080")
}

func main() {
idFlake = NewIDFlake(8, time.Now())
httpRun()
}

client:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# coding: utf-8

import requests


def main():
while True:
res = requests.get('http://127.0.0.1:8080/get_id').json()
print res
if res.get('error'):
break


if __name__ == '__main__':
main()

Run

server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)

[GIN-debug] Listening and serving HTTP on :8080
[2020-04-01 16:11:05] INFO slept for 285.71300000ms
[2020-04-01 16:11:06] INFO slept for 446.46500000ms
[2020-04-01 16:11:06] INFO slept for 450.56500000ms
[2020-04-01 16:11:07] INFO slept for 449.93100000ms
......
[2020-04-01 16:13:08] INFO slept for 449.52100000ms
[2020-04-01 16:13:09] INFO slept for 441.43400000ms
[2020-04-01 16:13:09] INFO slept for 434.80600000ms
[2020-04-01 16:13:10] INFO slept for 445.62500000ms
[2020-04-01 16:13:10] INFO slept for 444.83400000ms
[2020-04-01 16:13:11] INFO slept for 437.82700000ms
[2020-04-01 16:13:11] WARN getID error: over the time limit

client:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{u'machine': 0, u'tick': 4, u'id': 1024, u'sequence': 0}
{u'machine': 0, u'tick': 4, u'id': 1025, u'sequence': 1}
{u'machine': 0, u'tick': 4, u'id': 1026, u'sequence': 2}
{u'machine': 0, u'tick': 4, u'id': 1027, u'sequence': 3}
{u'machine': 0, u'tick': 4, u'id': 1028, u'sequence': 4}
{u'machine': 0, u'tick': 4, u'id': 1029, u'sequence': 5}
{u'machine': 0, u'tick': 4, u'id': 1030, u'sequence': 6}
{u'machine': 0, u'tick': 4, u'id': 1031, u'sequence': 7}
{u'machine': 0, u'tick': 4, u'id': 1032, u'sequence': 8}
{u'machine': 0, u'tick': 4, u'id': 1033, u'sequence': 9}
{u'machine': 0, u'tick': 4, u'id': 1034, u'sequence': 10}
{u'machine': 0, u'tick': 4, u'id': 1035, u'sequence': 11}
{u'machine': 0, u'tick': 4, u'id': 1036, u'sequence': 12}
{u'machine': 0, u'tick': 4, u'id': 1037, u'sequence': 13}
{u'machine': 0, u'tick': 4, u'id': 1038, u'sequence': 14}
{u'machine': 0, u'tick': 4, u'id': 1039, u'sequence': 15}
{u'machine': 0, u'tick': 5, u'id': 1280, u'sequence': 0}
{u'machine': 0, u'tick': 5, u'id': 1281, u'sequence': 1}
{u'machine': 0, u'tick': 5, u'id': 1282, u'sequence': 2}
{u'machine': 0, u'tick': 5, u'id': 1283, u'sequence': 3}
{u'machine': 0, u'tick': 5, u'id': 1284, u'sequence': 4}
......
{u'machine': 0, u'tick': 254, u'id': 65037, u'sequence': 13}
{u'machine': 0, u'tick': 254, u'id': 65038, u'sequence': 14}
{u'machine': 0, u'tick': 254, u'id': 65039, u'sequence': 15}
{u'machine': 0, u'tick': 255, u'id': 65280, u'sequence': 0}
{u'machine': 0, u'tick': 255, u'id': 65281, u'sequence': 1}
{u'machine': 0, u'tick': 255, u'id': 65282, u'sequence': 2}
{u'machine': 0, u'tick': 255, u'id': 65283, u'sequence': 3}
{u'machine': 0, u'tick': 255, u'id': 65284, u'sequence': 4}
{u'machine': 0, u'tick': 255, u'id': 65285, u'sequence': 5}
{u'machine': 0, u'tick': 255, u'id': 65286, u'sequence': 6}
{u'machine': 0, u'tick': 255, u'id': 65287, u'sequence': 7}
{u'machine': 0, u'tick': 255, u'id': 65288, u'sequence': 8}
{u'machine': 0, u'tick': 255, u'id': 65289, u'sequence': 9}
{u'machine': 0, u'tick': 255, u'id': 65290, u'sequence': 10}
{u'machine': 0, u'tick': 255, u'id': 65291, u'sequence': 11}
{u'machine': 0, u'tick': 255, u'id': 65292, u'sequence': 12}
{u'machine': 0, u'tick': 255, u'id': 65293, u'sequence': 13}
{u'machine': 0, u'tick': 255, u'id': 65294, u'sequence': 14}
{u'machine': 0, u'tick': 255, u'id': 65295, u'sequence': 15}
{u'error': u'over the time limit'}

Reference

Token bucket

Over the long run the output of conformant packets is limited by the token rate, \({\displaystyle r}\).

Implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package main

import (
"os"
"sync"
"time"

logger "github.com/sirupsen/logrus"
"github.com/x-cray/logrus-prefixed-formatter"
)

func init() {
logger.SetFormatter(&prefixed.TextFormatter{
TimestampFormat: "2006-01-02 15:04:05",
FullTimestamp: true,
ForceFormatting: true,
DisableColors: true,
})
logger.SetOutput(os.Stdout)
logger.SetLevel(logger.DebugLevel)
}

type TokenBucket struct {
mu sync.Mutex
startTime time.Time
availableTokens int64
capacity int64
fillInterval time.Duration
lastTick int64
}

func NewTokenBucket(qps, capacity int64) *TokenBucket {
return &TokenBucket{
startTime: time.Now(),
availableTokens: capacity,
capacity: capacity,
lastTick: 0,
fillInterval: time.Duration(int64(time.Second) / qps),
}
}

func (tb *TokenBucket) adjust() {
if (tb.availableTokens) >= tb.capacity {
return
}
now := time.Now()
tick := int64(now.Sub(tb.startTime) / tb.fillInterval)
tb.availableTokens += tick - tb.lastTick
if tb.availableTokens > tb.capacity {
tb.availableTokens = tb.capacity
}
tb.lastTick = tick
}

func (tb *TokenBucket) TakeAvailable(count int64) int64 {
tb.mu.Lock()
defer tb.mu.Unlock()

tb.adjust()

if tb.availableTokens <= 0 {
return 0
}

if count >= tb.availableTokens {
count = tb.availableTokens
}

tb.availableTokens -= count
return count
}

func task(qps, num int64, timeNeed time.Duration) {
logger.Infof("task qps: %v, num: %v, timeNeed: %.3fs", qps, num, timeNeed.Seconds())
bucket := NewTokenBucket(qps, qps)
startTime := time.Now()
lastTime := startTime

for i := int64(1); i <= num; {
if bucket.TakeAvailable(1) == 1 {
time.Sleep(timeNeed)
i++
if i%1000 == 0 {
now := time.Now()
logger.Infof("rate: %.3f", 1000/now.Sub(lastTime).Seconds())
lastTime = now
}
}
}

logger.Infof("task over, used: %.3fs", time.Now().Sub(startTime).Seconds())
}

func main() {
task(10000, 100000, 0)
task(10000, 15000, 2*time.Millisecond)
task(500, 10000, 0)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
[2020-03-31 15:58:49]  INFO task qps: 10000, num: 100000, timeNeed: 0.000s
[2020-03-31 15:58:49] INFO rate: 6698910.757
[2020-03-31 15:58:49] INFO rate: 6132110.182
[2020-03-31 15:58:49] INFO rate: 6394802.305
[2020-03-31 15:58:49] INFO rate: 6386511.687
[2020-03-31 15:58:49] INFO rate: 5484591.041
[2020-03-31 15:58:49] INFO rate: 6646770.666
[2020-03-31 15:58:49] INFO rate: 5725671.621
[2020-03-31 15:58:49] INFO rate: 6449490.813
[2020-03-31 15:58:49] INFO rate: 5718631.875
[2020-03-31 15:58:49] INFO rate: 6620981.892
[2020-03-31 15:58:49] INFO rate: 10174.362
[2020-03-31 15:58:49] INFO rate: 9999.993
[2020-03-31 15:58:49] INFO rate: 9999.979
[2020-03-31 15:58:49] INFO rate: 10000.032
[2020-03-31 15:58:49] INFO rate: 9999.993
[2020-03-31 15:58:49] INFO rate: 10000.001
[2020-03-31 15:58:50] INFO rate: 9999.981
[2020-03-31 15:58:50] INFO rate: 9750.039
[2020-03-31 15:58:50] INFO rate: 10263.124
[2020-03-31 15:58:50] INFO rate: 10000.008
[2020-03-31 15:58:50] INFO rate: 10000.004
[2020-03-31 15:58:50] INFO rate: 10000.006
[2020-03-31 15:58:50] INFO rate: 9999.980
[2020-03-31 15:58:50] INFO rate: 10000.013
[2020-03-31 15:58:50] INFO rate: 10000.008
[2020-03-31 15:58:50] INFO rate: 9999.989
[2020-03-31 15:58:51] INFO rate: 10000.006
[2020-03-31 15:58:51] INFO rate: 10000.002
[2020-03-31 15:58:51] INFO rate: 10000.002
[2020-03-31 15:58:51] INFO rate: 9999.990
[2020-03-31 15:58:51] INFO rate: 9999.990
[2020-03-31 15:58:51] INFO rate: 10000.004
[2020-03-31 15:58:51] INFO rate: 10000.008
[2020-03-31 15:58:51] INFO rate: 10000.004
[2020-03-31 15:58:51] INFO rate: 9999.999
[2020-03-31 15:58:51] INFO rate: 9999.994
[2020-03-31 15:58:52] INFO rate: 10000.011
[2020-03-31 15:58:52] INFO rate: 9999.991
[2020-03-31 15:58:52] INFO rate: 9865.780
[2020-03-31 15:58:52] INFO rate: 10137.923
[2020-03-31 15:58:52] INFO rate: 9999.998
[2020-03-31 15:58:52] INFO rate: 10000.009
[2020-03-31 15:58:52] INFO rate: 10000.000
[2020-03-31 15:58:52] INFO rate: 9999.998
[2020-03-31 15:58:52] INFO rate: 10000.000
[2020-03-31 15:58:52] INFO rate: 10000.000
[2020-03-31 15:58:53] INFO rate: 10000.002
[2020-03-31 15:58:53] INFO rate: 10000.006
[2020-03-31 15:58:53] INFO rate: 9999.994
[2020-03-31 15:58:53] INFO rate: 9999.992
[2020-03-31 15:58:53] INFO rate: 9999.989
[2020-03-31 15:58:53] INFO rate: 10000.026
[2020-03-31 15:58:53] INFO rate: 9999.996
[2020-03-31 15:58:53] INFO rate: 10000.001
[2020-03-31 15:58:53] INFO rate: 9999.975
[2020-03-31 15:58:53] INFO rate: 10000.015
[2020-03-31 15:58:54] INFO rate: 10000.008
[2020-03-31 15:58:54] INFO rate: 9999.993
[2020-03-31 15:58:54] INFO rate: 10000.011
[2020-03-31 15:58:54] INFO rate: 9998.373
[2020-03-31 15:58:54] INFO rate: 10001.612
[2020-03-31 15:58:54] INFO rate: 10000.003
[2020-03-31 15:58:54] INFO rate: 10000.010
[2020-03-31 15:58:54] INFO rate: 10000.000
[2020-03-31 15:58:54] INFO rate: 10000.000
[2020-03-31 15:58:54] INFO rate: 9999.988
[2020-03-31 15:58:55] INFO rate: 10000.005
[2020-03-31 15:58:55] INFO rate: 10000.007
[2020-03-31 15:58:55] INFO rate: 9999.996
[2020-03-31 15:58:55] INFO rate: 9999.999
[2020-03-31 15:58:55] INFO rate: 9999.976
[2020-03-31 15:58:55] INFO rate: 10000.032
[2020-03-31 15:58:55] INFO rate: 9999.998
[2020-03-31 15:58:55] INFO rate: 10000.000
[2020-03-31 15:58:55] INFO rate: 9999.990
[2020-03-31 15:58:55] INFO rate: 10000.001
[2020-03-31 15:58:56] INFO rate: 9999.999
[2020-03-31 15:58:56] INFO rate: 9999.993
[2020-03-31 15:58:56] INFO rate: 10000.012
[2020-03-31 15:58:56] INFO rate: 10000.001
[2020-03-31 15:58:56] INFO rate: 10000.005
[2020-03-31 15:58:56] INFO rate: 9999.996
[2020-03-31 15:58:56] INFO rate: 9999.993
[2020-03-31 15:58:56] INFO rate: 9999.999
[2020-03-31 15:58:56] INFO rate: 10000.008
[2020-03-31 15:58:56] INFO rate: 9999.996
[2020-03-31 15:58:57] INFO rate: 9998.998
[2020-03-31 15:58:57] INFO rate: 10001.010
[2020-03-31 15:58:57] INFO rate: 9999.992
[2020-03-31 15:58:57] INFO rate: 10000.004
[2020-03-31 15:58:57] INFO rate: 9999.997
[2020-03-31 15:58:57] INFO rate: 9999.988
[2020-03-31 15:58:57] INFO rate: 10000.012
[2020-03-31 15:58:57] INFO rate: 9999.996
[2020-03-31 15:58:57] INFO rate: 10000.012
[2020-03-31 15:58:57] INFO rate: 9999.998
[2020-03-31 15:58:58] INFO rate: 9999.991
[2020-03-31 15:58:58] INFO rate: 9999.990
[2020-03-31 15:58:58] INFO rate: 10000.020
[2020-03-31 15:58:58] INFO rate: 9999.995
[2020-03-31 15:58:58] INFO task over, used: 9.000s
[2020-03-31 15:58:58] INFO task qps: 10000, num: 15000, timeNeed: 0.002s
[2020-03-31 15:59:00] INFO rate: 397.098
[2020-03-31 15:59:03] INFO rate: 396.814
[2020-03-31 15:59:05] INFO rate: 397.583
[2020-03-31 15:59:08] INFO rate: 391.641
[2020-03-31 15:59:10] INFO rate: 391.799
[2020-03-31 15:59:13] INFO rate: 400.202
[2020-03-31 15:59:15] INFO rate: 402.581
[2020-03-31 15:59:18] INFO rate: 405.188
[2020-03-31 15:59:20] INFO rate: 396.681
[2020-03-31 15:59:23] INFO rate: 397.131
[2020-03-31 15:59:25] INFO rate: 398.076
[2020-03-31 15:59:28] INFO rate: 398.811
[2020-03-31 15:59:30] INFO rate: 399.199
[2020-03-31 15:59:33] INFO rate: 400.549
[2020-03-31 15:59:36] INFO rate: 390.775
[2020-03-31 15:59:36] INFO task over, used: 37.732s
[2020-03-31 15:59:36] INFO task qps: 500, num: 10000, timeNeed: 0.000s
[2020-03-31 15:59:37] INFO rate: 1002.004
[2020-03-31 15:59:39] INFO rate: 500.000
[2020-03-31 15:59:41] INFO rate: 500.000
[2020-03-31 15:59:43] INFO rate: 500.000
[2020-03-31 15:59:45] INFO rate: 500.000
[2020-03-31 15:59:47] INFO rate: 500.000
[2020-03-31 15:59:49] INFO rate: 500.000
[2020-03-31 15:59:51] INFO rate: 500.000
[2020-03-31 15:59:53] INFO rate: 500.000
[2020-03-31 15:59:55] INFO rate: 500.000
[2020-03-31 15:59:55] INFO task over, used: 19.000s

Comparison sorts

Name Best Average Worst Memory Stable
Bubble sort \(n\) \(n^2\) \(n^2\) \(1\) Yes
Insertion sort \(n\) \(n^2\) \(n^2\) \(1\) Yes
Merge sort \(n\log n\) \(n\log n\) \(n\log n\) \(n\) Yes
Heapsort \(n\log n\) \(n\log n\) \(n\log n\) \(1\) No
Quicksort \(n\log n\) \(n\log n\) \(n^2\) \(\log n\) No

External sort

External sorting

external.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <bits/stdc++.h>
#define DBG(x) cerr << #x << " = " << x << endl

using namespace std;
typedef long long LL;

const int MAX_MEM = 128 * 1024 * 1024; // 128MB
const int BUF_SIZE = 64;

string write_temp_file(int file_no, const vector<string> &strings) {
string temp_file = to_string(file_no) + ".txt";
FILE *f_temp = fopen(temp_file.c_str(), "w");

for (const auto &s : strings) {
fputs(s.c_str(), f_temp);
}
fclose(f_temp);

return temp_file;
}

vector<string> sort_part_to_disk(const string &input_file) {
vector<string> temp_files;

FILE *f_input = fopen(input_file.c_str(), "r");

int temp_size = 0;
int file_no = 0;
char buf[BUF_SIZE];
vector<string> strings;

while (fgets(buf, sizeof(buf) - 1, f_input) != NULL) {
string str = buf;
temp_size += str.size();
strings.push_back(str);

if (temp_size >= MAX_MEM) {
sort(strings.begin(), strings.end());
string temp_file = write_temp_file(file_no, strings);
temp_files.push_back(temp_file);

file_no++;
strings.clear();
temp_size = 0;
}
}

if (!strings.empty()) {
sort(strings.begin(), strings.end());
string temp_file = write_temp_file(file_no, strings);
temp_files.push_back(temp_file);
}

fclose(f_input);

return temp_files;
}

void external_sort(const string &input_file, const string &output_file) {
vector<string> temp_files = sort_part_to_disk(input_file);
vector<FILE *> files;
for (const auto &file_name : temp_files) {
FILE *temp_file = fopen(file_name.c_str(), "r");
files.push_back(temp_file);
}

FILE *f_output = fopen(output_file.c_str(), "w");

priority_queue<pair<string, string>, vector<pair<string, string>>, greater<pair<string, string>>> pri_que;

bool have_input = false;
do {
have_input = false;

for (int i = 0; i < temp_files.size(); i++) {
char buf[BUF_SIZE];
if (fgets(buf, sizeof(buf) - 1, files[i]) != NULL) {
have_input = true;
pri_que.push(pair<string, string>(buf, temp_files[i]));
}
}

if (!pri_que.empty()) {
pair<string, string> top = pri_que.top();
pri_que.pop();
fputs(top.first.c_str(), f_output);
}

} while (have_input || !pri_que.empty());

for (FILE *f : files) {
fclose(f);
}
fclose(f_output);
}

int main(int argc, char **argv) {
external_sort("raw.txt", "output.txt");
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 torapture@localhost ~/SSD/Codes/acm ls -lh raw.txt
-rwxrwxrwx 1 torapture staff 685M 3 30 18:02 raw.txt

torapture@localhost ~/SSD/Codes/acm time ./external
./external 617.04s user 17.50s system 94% cpu 11:10.99 total

torapture@localhost ~/SSD/Codes/acm time sort ./raw.txt > sort.txt
sort ./raw.txt > sort.txt 496.36s user 87.25s system 81% cpu 11:58.01 total

torapture@localhost ~/SSD/Codes/acm ls -lh raw.txt output.txt sort.txt
-rwxrwxrwx 1 torapture staff 685M 3 30 18:13 output.txt
-rwxrwxrwx 1 torapture staff 685M 3 30 18:02 raw.txt
-rwxrwxrwx 1 torapture staff 685M 3 30 18:28 sort.txt
torapture@localhost ~/SSD/Codes/acm diff output.txt sort.txt

Reference

Go maps in action Comparison operators

Declaration and initialization

A Go map type looks like this: map[KeyType]ValueType where KeyType may be any type that is comparable (more on this later), and ValueType may be any type at all, including another map!

Key types

As mentioned earlier, map keys may be of any type that is comparable. The language spec defines this precisely, but in short, comparable types are boolean, numeric, string, pointer, channel, and interface types, and structs or arrays that contain only those types. Notably absent from the list are slices, maps, and functions; these types cannot be compared using ==, and may not be used as map keys.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main

import (
"os"

logger "github.com/sirupsen/logrus"
"github.com/x-cray/logrus-prefixed-formatter"
)

func init() {
logger.SetFormatter(&prefixed.TextFormatter{
TimestampFormat: "2006-01-02 15:04:05",
FullTimestamp: true,
ForceFormatting: true,
DisableColors: true,
})
logger.SetOutput(os.Stdout)
logger.SetLevel(logger.DebugLevel)
}

type Foo struct {
Y interface{}
}

func main() {
mp := map[Foo]int{
Foo{
Y: [...]int{1, 2, 3},
}: 256,
}
logger.Infof("mp: %+v", mp)

mp = map[Foo]int{
Foo{
Y: map[int]int{},
}: 256,
}
logger.Infof("mp: %+v", mp)
}

Results:

1
2
3
4
5
6
panic: runtime error: hash of unhashable type map[int]int
[2020-03-30 15:06:32] INFO mp: map[{Y:[1 2 3]}:256]

goroutine 1 [running]:
main.main()
/Users/torapture/Codes/repos/go/src/go-learn/main.go:33 +0x1a2