Skip to content

Commit b57ec49

Browse files
author
Smallfly
committed
BM match by Objective-C
1 parent d4eba0b commit b57ec49

File tree

4 files changed

+180
-2
lines changed

4 files changed

+180
-2
lines changed

java/17_skiplist/SkipList.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,22 @@ public void insert(int value) {
4343
update[i] = head;
4444
}
4545

46+
// record every level largest value which smaller than insert value in update[]
4647
Node p = head;
4748
for (int i = level - 1; i >= 0; --i) {
4849
while (p.forwords[i] != null && p.forwords[i].data < value) {
4950
p = p.forwords[i];
5051
}
51-
update[i] = p;
52+
update[i] = p;// use update save node in search path
5253
}
5354

55+
// in search path node next node become new node forwords(next)
5456
for (int i = 0; i < level; ++i) {
5557
newNode.forwords[i] = update[i].forwords[i];
5658
update[i].forwords[i] = newNode;
5759
}
5860

61+
// update node hight
5962
if (levelCount < level) levelCount = level;
6063
}
6164

@@ -78,7 +81,8 @@ public void delete(int value) {
7881
}
7982
}
8083

81-
private int randomLevel() {
84+
// 随机 level 次,如果是奇数层数 +1,防止伪随机
85+
private int randomLevel() {
8286
int level = 1;
8387
for (int i = 1; i < MAX_LEVEL; ++i) {
8488
if (r.nextInt() % 2 == 1) {
@@ -100,6 +104,7 @@ public void printAll() {
100104

101105
public class Node {
102106
private int data = -1;
107+
// 以数组形式维护下一个结点的指针
103108
private Node forwords[] = new Node[MAX_LEVEL];
104109
private int maxLevel = 0;
105110

object-c/33_bm_match/BM.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// BM.h
3+
// BM-Match
4+
//
5+
// Created by Smallfly on 2018/12/9.
6+
// Copyright © 2018 Smallfly. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
11+
NS_ASSUME_NONNULL_BEGIN
12+
13+
@interface BM : NSObject
14+
- (instancetype)initWithA:(NSString *)a andB:(NSString *)b;
15+
- (NSInteger)startMatch;
16+
- (void)startMatchCompeletion:(void (^)(NSInteger))completion;
17+
@end
18+
19+
NS_ASSUME_NONNULL_END

object-c/33_bm_match/BM.m

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//
2+
// BM.m
3+
// BM-Match
4+
//
5+
// Created by Smallfly on 2018/12/9.
6+
// Copyright © 2018 Smallfly. All rights reserved.
7+
//
8+
9+
#import "BM.h"
10+
11+
#define SIZE 256
12+
13+
@interface BM()
14+
@property (nonatomic, strong) NSString *a; // 主串
15+
@property (nonatomic, strong) NSString *b; // 匹配串
16+
17+
@property (nonatomic, strong) NSMutableArray *bc; // 匹配串,哈希表,存储字符在匹配串中的下标
18+
19+
@property (nonatomic, strong) NSMutableArray *suffix;
20+
@property (nonatomic, strong) NSMutableArray *prifix;
21+
22+
@end
23+
24+
@implementation BM
25+
26+
- (instancetype)initWithA:(NSString *)a andB:(NSString *)b {
27+
self = [super init];
28+
if (!self) return nil;
29+
_a = a;
30+
_b = b;
31+
_bc = [NSMutableArray new];
32+
_suffix = [NSMutableArray new];
33+
_prifix = [NSMutableArray new];
34+
[self generateBC];
35+
[self generateGS];
36+
return self;
37+
}
38+
39+
// 构建坏字符哈希表,记录每个字符在匹配串中最后出现的位置
40+
- (void)generateBC {
41+
for (int i = 0; i < SIZE; ++i) {
42+
[_bc addObject:@-1];
43+
}
44+
for (int i = 0; i < _b.length; ++i) {
45+
int ascii = (int)[_b characterAtIndex:i]; // char to ASCII
46+
_bc[ascii] = [NSNumber numberWithInteger:i]; // save b's char index
47+
}
48+
}
49+
50+
- (NSInteger)bm {
51+
NSInteger i = 0; // 主串和匹配串对齐的第一个字符
52+
NSUInteger n = _a.length;
53+
NSUInteger m = _b.length;
54+
while (i <= n - m) {
55+
NSInteger j;
56+
// 从后往前匹配
57+
for (j = m - 1; j >= 0; --j) {
58+
int aValue = (int)[_a characterAtIndex:(i + j)];
59+
int bValue = (int)[_b characterAtIndex:j];
60+
if (aValue != bValue) break; // 找到坏字符下标 j 停止
61+
}
62+
if (j < 0) {
63+
return i; // 匹配成功,返回所在的位置
64+
}
65+
66+
// 坏字符在匹配串中最后出现的位置
67+
id numberInHashTableBC = _bc[(int)[_a characterAtIndex:(i + j)]];
68+
NSInteger x = j - [numberInHashTableBC integerValue];
69+
NSInteger y = 0;
70+
if (j < m - 1) {
71+
y = [self moveByGSBy:j];
72+
}
73+
i = i + MAX(x, y);
74+
75+
// 这一步比较难理解,不直接滑到过 j,是因为在 j 之前可能存在于坏字符相同的字符
76+
// 这个于坏字符相同的字符,在匹配串中的最大下标是 numberInHashTableBC
77+
// i = i + (j - [numberInHashTableBC integerValue]);
78+
}
79+
80+
return -1;
81+
}
82+
83+
// 好后缀匹配移动
84+
- (NSInteger)moveByGSBy:(NSInteger)j {
85+
NSUInteger m = _b.length;
86+
NSInteger k = m - 1 - j; // 好后缀的长度
87+
NSInteger t = [_suffix[k] integerValue];
88+
if (t != -1) return j - t + 1; // 匹配串的前缀,是否匹配好后缀,关键
89+
for (NSInteger r = j+1; r <= m-1; ++r) {
90+
if ([_prifix[m-r] boolValue]) { // 关键
91+
return r;
92+
}
93+
}
94+
return m;
95+
}
96+
97+
- (void)generateGS {
98+
NSUInteger m = _b.length;
99+
for (NSInteger i = 0; i < m; ++i) {
100+
_prifix[i] = @(NO);
101+
_suffix[i] = @(-1);
102+
}
103+
for (NSInteger i = 0; i < m - 1; ++i) { // 从 b 中取两个字符对比
104+
NSInteger j = i;
105+
NSInteger k = 0; // 公共后缀的长度
106+
int jValue = (int)[_b characterAtIndex:j];
107+
int bmValue = (int)[_b characterAtIndex:(m-1-k)];
108+
while (j >= 0 && jValue == bmValue) { // 与 b[0, m-1] 求公共子串
109+
++k;
110+
--j;
111+
_suffix[k] = [NSNumber numberWithInteger:(j+1)]; //j+1 代表公共子串在 b 中的起始下标
112+
}
113+
if (j == -1) _prifix[k] = @(YES);
114+
}
115+
}
116+
117+
#pragma mark -
118+
119+
// 同步
120+
- (NSInteger)startMatch {
121+
return [self bm];
122+
}
123+
124+
// 异步
125+
- (void)startMatchCompeletion:(void (^)(NSInteger))completion {
126+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
127+
completion([self bm]);
128+
});
129+
}
130+
131+
@end

object-c/33_bm_match/main.m

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// main.m
3+
// BM-Match
4+
//
5+
// Created by Smallfly on 2018/12/9.
6+
// Copyright © 2018 Smallfly. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
#import "BM.h"
11+
12+
int main(int argc, const char * argv[]) {
13+
@autoreleasepool {
14+
BM *bm = [[BM alloc] initWithA:@"abacadc" andB:@"adc"];
15+
16+
[bm startMatchCompeletion:^(NSInteger index) {
17+
NSLog(@"异步查找到下标:%ld\n", index);
18+
}];
19+
20+
NSLog(@"同步查找到下标:%ld\n", [bm startMatch]);
21+
}
22+
return 0;
23+
}

0 commit comments

Comments
 (0)