Vâng, tôi đã tìm thấy cách nhanh hơn 30 lần — mặc dù, cho là gian lận của nó. Tôi đã bao gồm mã Benchmark.pm để chuẩn nó, vì bạn dường như không quen thuộc với nó.
Điểm chuẩn là:
Rate Join Cheat
Join 83294/s -- -97%
Cheat 2580687/s 2998% --
Và mã. Sau khi dòng thứ ba, tôi nghĩ bạn sẽ hiểu tại sao gian lận cho là của nó:
use v5.14;
use Benchmark qw(cmpthese);
use Inline 'C';
sub an_join {
my ($s1, $s2) = @_;
return (join '', sort split(//, $s1)) eq
(join '', sort split(//, $s2));
}
use constant {
STR1 => 'abcdefghijklm',
STR2 => 'abcdefghijkmm',
STR3 => 'abcdefghijkml',
};
cmpthese(
0,
{
'Join' => 'an_join(STR1, STR2); an_join(STR1, STR3)',
'Cheat' => 'an_cheat(STR1, STR2); an_cheat(STR1, STR3)',
});
__END__
__C__
int an_cheat(const char *a, const char *b) {
unsigned char vec_a[26], vec_b[26];
const char *p, *end;
memset(vec_a, 0, sizeof(vec_a));
memset(vec_b, 0, sizeof(vec_b));
end = a+strlen(a);
for (p = a; p < end; ++p)
if (*p >= 'a' && *p <= 'z')
++vec_a[(*p)-'a'];
end = b+strlen(b);
for (p = b; p < end; ++p)
if (*p >= 'a' && *p <= 'z')
++vec_b[(*p)-'a'];
return 0 == memcmp(vec_a, vec_b, sizeof(vec_a));
}
Tất nhiên, gian lận của nó bởi vì nó không được viết bằng Perl-nó trong C. Ngoài ra, nó có những hạn chế của phiên bản Perl không (chỉ hoạt động với các ký tự ASCII chữ thường là quan trọng nhất — nó chỉ bỏ qua mọi thứ khác). Nhưng nếu bạn thực sự cần tốc độ, bạn có thể sử dụng gian lận như thế này.
chỉnh sửa:
Mở rộng cho tất cả Latin1 (ký tự 8 bit thật, thực sự). Ngoài ra, tôi thấy rằng trình biên dịch quản lý để tối ưu hóa một vòng lặp đơn giản hơn (không có điểm số học) tốt hơn, và dễ đọc hơn, vì vậy ... Benchmark cho tôi biết rằng phiên bản chỉ ASCII chỉ là khoảng 10% nhanh hơn:
int an_cheat_l1b(const char *a, const char *b) {
unsigned char vec_a[UCHAR_MAX], vec_b[UCHAR_MAX];
size_t len, i;
memset(vec_a, 0, sizeof(vec_a));
memset(vec_b, 0, sizeof(vec_b));
len = strlen(a);
for (i = 0; i < len; ++i)
++vec_a[((const unsigned char *)(a))[i]];
len = strlen(b);
for (i = 0; i < len; ++i)
++vec_b[((const unsigned char *)(b))[i]];
return 0 == memcmp(vec_a, vec_b, sizeof(vec_a));
}
Lưu ý rằng lợi thế của phiên bản C phát triển khi chuỗi dài hơn — được mong đợi, vì Θ (n) trái với phiên bản Perl O (n · logn). Ngoài ra hình phạt cho toàn Latin1 giảm, có nghĩa là hình phạt có lẽ là memcmp.
Đọc thú vị để so sánh mảng: http://stackoverflow.com/questions/1609467/in-perl-is-there-a-built-in-way-to-compare-two-arrays-for-equality – Mat
Bạn cũng có thể so sánh độ dài chuỗi và trả về false nếu độ dài chuỗi khác nhau, để tránh phải sắp xếp các chuỗi chắc chắn không phải là đảo chữ cái. Đối với các chuỗi có cùng độ dài, so sánh chiều dài rất nhanh, nhanh hơn nhiều so với chia tách phân loại, vì vậy, hiệu suất đạt được sẽ không đáng kể. –
Vâng, bạn có thể cải thiện hiệu suất bằng cách loại bỏ hàm so sánh - bạn không cần nó: 'join '', phân loại phân tách (//, $ s1)'. – derobert