|
1 | 1 | package base |
2 | 2 |
|
3 | | -import ( |
4 | | - "sort" |
5 | | -) |
6 | | - |
7 | 3 | type VoteResult string |
8 | 4 |
|
9 | 5 | const ( |
@@ -47,86 +43,74 @@ func (v *VoteResult) UnmarshalText(b []byte) error { |
47 | 43 | return nil |
48 | 44 | } |
49 | 45 |
|
50 | | -// FindMajority finds the majority(over threshold) set between the given sets. |
51 | | -// The returned value means, |
52 | | -// 0-N: index number of set |
53 | | -// -1: not yet majority |
54 | | -// -2: draw |
55 | | -func FindMajority(quorum, threshold uint, set ...uint) int { |
| 46 | +func FindVoteResult(quorum, threshold uint, s []string) (result VoteResult, key string) { |
56 | 47 | th := threshold |
57 | 48 | if th > quorum { |
58 | 49 | th = quorum |
59 | 50 | } |
60 | | - |
61 | | - if len(set) < 1 { |
62 | | - return -1 |
| 51 | + if len(s) == 0 { |
| 52 | + return VoteResultNotYet, "" |
63 | 53 | } |
64 | 54 |
|
65 | | - var sum uint |
66 | | - |
67 | | - for i := range set { |
68 | | - n := set[i] |
69 | | - |
70 | | - if n >= quorum { |
71 | | - return i |
72 | | - } |
| 55 | + count := make(map[string]uint, len(s)) |
| 56 | + for _, v := range s { |
| 57 | + count[v]++ |
| 58 | + } |
73 | 59 |
|
74 | | - if n >= th { |
75 | | - return i |
| 60 | + var ( |
| 61 | + maxCount uint |
| 62 | + secondMaxCount uint |
| 63 | + topTies uint |
| 64 | + mhs string |
| 65 | + ) |
| 66 | + |
| 67 | + for hs, cn := range count { |
| 68 | + switch { |
| 69 | + case cn > maxCount: |
| 70 | + secondMaxCount = maxCount |
| 71 | + maxCount = cn |
| 72 | + mhs = hs |
| 73 | + topTies = 1 |
| 74 | + case cn == maxCount: |
| 75 | + topTies++ |
| 76 | + if hs < mhs { |
| 77 | + mhs = hs |
| 78 | + } |
| 79 | + case cn > secondMaxCount: |
| 80 | + secondMaxCount = cn |
76 | 81 | } |
77 | | - |
78 | | - sum += n |
79 | 82 | } |
80 | 83 |
|
81 | | - sort.Slice(set, func(i, j int) bool { |
82 | | - return set[i] > set[j] |
83 | | - }) |
84 | | - |
85 | | - if quorum-sum+set[0] < th { |
86 | | - return -2 |
| 84 | + total := uint(len(s)) |
| 85 | + var remain uint |
| 86 | + if total >= quorum { |
| 87 | + remain = 0 |
| 88 | + } else { |
| 89 | + remain = quorum - total |
87 | 90 | } |
88 | 91 |
|
89 | | - return -1 |
90 | | -} |
91 | | - |
92 | | -func FindVoteResult(quorum, threshold uint, s []string) (result VoteResult, key string) { |
93 | | - th := threshold |
94 | | - if th > quorum { |
95 | | - th = quorum |
| 92 | + if maxCount >= th { |
| 93 | + return VoteResultMajority, mhs |
96 | 94 | } |
97 | 95 |
|
98 | | - if len(s) < 1 { |
99 | | - return VoteResultNotYet, "" |
| 96 | + if remain == 0 { |
| 97 | + return VoteResultDraw, "" |
100 | 98 | } |
101 | 99 |
|
102 | | - keys := map[uint]string{} |
103 | | - defer clear(keys) |
104 | | - |
105 | | - count := map[string]uint{} |
106 | | - defer clear(count) |
107 | | - |
108 | | - for i := range s { |
109 | | - count[s[i]]++ |
| 100 | + if topTies > 1 { |
| 101 | + if maxCount+remain < th { |
| 102 | + return VoteResultDraw, "" |
| 103 | + } |
| 104 | + return VoteResultNotYet, "" |
110 | 105 | } |
111 | 106 |
|
112 | | - set := make([]uint, len(count)) |
113 | | - var i int |
114 | | - |
115 | | - for j := range count { |
116 | | - c := count[j] |
117 | | - keys[c] = j |
118 | | - set[i] = c |
119 | | - i++ |
| 107 | + maxPossible := maxCount + remain |
| 108 | + if maxPossible < th { |
| 109 | + return VoteResultDraw, "" |
120 | 110 | } |
121 | | - |
122 | | - sort.Slice(set, func(i, j int) bool { return set[i] > set[j] }) |
123 | | - |
124 | | - switch index := FindMajority(quorum, th, set...); index { |
125 | | - case -1: |
126 | | - return VoteResultNotYet, "" |
127 | | - case -2: |
| 111 | + if secondMaxCount+remain <= maxCount && maxPossible <= th { |
128 | 112 | return VoteResultDraw, "" |
129 | | - default: |
130 | | - return VoteResultMajority, keys[set[index]] |
131 | 113 | } |
| 114 | + |
| 115 | + return VoteResultNotYet, "" |
132 | 116 | } |
0 commit comments