- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
假设我们有一个数据数组和另一个带索引的数组。
data = [1, 2, 3, 4, 5, 7]
index = [5, 1, 4, 0, 2, 3]
我们想从 chỉ số
của dữ liệu
元素创建一个新数组。结果应该是
[4, 2, 5, 7, 3, 1]
朴素算法适用于 O(N),但它执行随机内存访问。
你能推荐具有相同复杂度的 CPU 缓存友好算法吗?
附言在我的特定情况下,数据数组中的所有元素都是整数。
公务员事务局数组可能包含数百万个元素。
PPPS 我接受 SSE/AVX 或任何其他 x64 特定优化
câu trả lời hay nhất
将索引和数据合并到一个数组中。然后使用一些缓存友好的排序算法对这些对进行排序(按索引)。然后摆脱索引。 (您可以将合并/删除索引与排序算法的第一遍/最后一遍结合起来对此进行一点优化)。
对于缓存友好的 O(N) 排序,使用具有足够小 radix
的基数排序(最多 CPU 缓存中缓存行数的一半)。
这是类基数排序算法的 C 实现:
void reorder2(const unsigned size)
{
const unsigned min_bucket = size / kRadix;
const unsigned large_buckets = size % kRadix;
g_counters[0] = 0;
for (unsigned i = 1; i <= large_buckets; ++i)
g_counters[i] = g_counters[i - 1] + min_bucket + 1;
for (unsigned i = large_buckets + 1; i < kRadix; ++i)
g_counters[i] = g_counters[i - 1] + min_bucket;
for (unsigned i = 0; i < size; ++i)
{
const unsigned dst = g_counters[g_index[i] % kRadix]++;
g_sort[dst].index = g_index[i] / kRadix;
g_sort[dst].value = g_input[i];
__builtin_prefetch(&g_sort[dst + 1].value, 1);
}
g_counters[0] = 0;
for (unsigned i = 1; i < (size + kRadix - 1) / kRadix; ++i)
g_counters[i] = g_counters[i - 1] + kRadix;
for (unsigned i = 0; i < size; ++i)
{
const unsigned dst = g_counters[g_sort[i].index]++;
g_output[dst] = g_sort[i].value;
__builtin_prefetch(&g_output[dst + 1], 1);
}
}
它在两个方面不同于基数排序:(1) 它不进行计数遍历,因为所有计数器都是预先知道的; (2) 避免使用基数的2次方值。
This C++ code was used for benchmarking (如果你想在 32 位系统上运行它,稍微减小 kMaxSize
常量)。
以下是基准测试结果(在具有 6Mb 缓存的 Haswell CPU 上):
很容易看出小型数组(少于 200 万个元素)即使对于朴素算法也是缓存友好的。此外,您可能会注意到排序方法在图表的最后一点开始对缓存不友好(size/radix
在 L3 缓存中接近 0.75 缓存行)。在这些限制之间,排序方法比朴素算法更有效。
理论上(如果我们仅将这些算法所需的内存带宽与 64 字节缓存行和 4 字节值进行比较)排序算法应该快 3 倍。实际上,我们的差异要小得多,大约 20%。如果我们为 dữ liệu
数组使用更小的 16 位值(在这种情况下,排序算法大约快 1.5 倍),这可能会有所改善。
排序方法的另一个问题是当 size/radix
接近某个 2 的幂时它的最坏情况行为。这可能会被忽略(因为没有那么多“坏”尺寸)或通过使该算法稍微复杂一些来解决。
如果我们将 channel 数增加到 3,则所有 3 个 channel 主要使用 L1 缓存,但内存带宽增加了 60%。我用这段代码得到了实验结果:TL; DR .在(通过实验)确定最佳基数值后,对于大于 4 000 000 的大小(其中 2-pass 算法使用 L3 缓存一次)我得到了更好的结果,但对于较小的数组(其中 2-pass 算法使用 L2缓存两次)。正如预期的那样,16 位数据的性能更好。
结论:性能差异远小于算法复杂度差异,因此朴素方法几乎总是更好;如果性能非常重要并且只使用 2 或 4 字节值,则排序方法更可取。
关于通过已知索引、收集、分散重新调整的数组缓存友好复制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34693853/
Câu hỏi này đã có câu trả lời ở đây: Phép thuật phương thức apply() của Scala hoạt động như thế nào? (3 câu trả lời) Đã đóng 9 năm trước. Giả sử tôi có một lớp MyList trong scala có
Câu hỏi này đã có câu trả lời ở đây: Nhóm không bắt giữ trong biểu thức chính quy là gì? (18 câu trả lời) Tham khảo - Làm gì
Câu hỏi này dành cho hệ thống nhúng! Tôi có các tùy chọn sau để khởi tạo một đối tượng: Object* o = new Object(arg); Thao tác này sẽ đặt đối tượng vào vùng nhớ heap và trả về một con trỏ tới nó. Tôi không thích sử dụng phân bổ động trong phần mềm nhúng. Ob
Tôi đã tự mình tìm kiếm các biểu thức thông thường nhưng không thành công. Tôi có một tệp html chứa các biến giữa [] và tôi muốn viết từng từ vào đó. [tên_khách_hàng][công_ty_khách_hàng] [cl
Tôi mới làm quen với Python. Tôi không hiểu tại sao mã này không hoạt động: reOptions = re.search( "[\s+@twitter\s+(?P\w+):(?P.*?)\s+]", d
Tôi hầu như chỉ lập trình bằng .NET C# trong khoảng 7 tháng qua. Trước đó, phần lớn chương trình của tôi là bằng C++ (học ở trường). Tại nơi làm việc, tôi có thể cần phải làm nhiều việc C trong vài tháng tới. Tôi quan tâm đến C
Tôi mới làm quen với RE và tôi đang cố gắng lấy lời bài hát và tách biệt tiêu đề lời bài hát, giọng hát đệm và giọng hát chính: Dưới đây là một số ví dụ về lời bài hát: [Intro] DA hiểu rồi [Điệp khúc: Travis Scott] Ic
Điều này có thể không thực hiện được, nhưng tôi muốn kiểm tra xem liệu có thể diễn đạt điều gì đó như thế này một cách đơn giản hay không: // rõ ràng là không hoạt động class Foo : IFoo Where T: Bar {
Chúng tôi có các thực thể "người dùng" và "nghiên cứu" trong ứng dụng của mình, được lưu trữ trong các bảng tương ứng. Một nghiên cứu đại diện cho một loại nghiên cứu và dữ liệu đã được thu thập. Chúng là mối quan hệ nhiều-nhiều, vì vậy chúng ta cần một bảng được liên kết: Studies_users. Chúng tôi chỉ định góc cho người dùng
Khi thêm các điều kiện kiểm tra vào Kiểm tra đơn vị cơ sở dữ liệu Visual Studio 2010 (dành cho SQL Server 2008), các điều kiện này được gọi, ví dụ: rowCountCondition1, rowCountConditio
Trên trình giả lập, tôi có thể ngắt kết nối thẻ SD khỏi cài đặt. Sau đó tôi có thể cài đặt nó trên hệ điều hành của mình và gỡ cài đặt bình thường. Tôi chưa thể tìm ra cách cài đặt lại nó trên trình giả lập (mà không cần khởi động lại). Mẹo: lệnh adb remount bị tắt
Giả sử một loạt các cam kết được thực hiện trên một nhánh, nhưng nhánh đó vẫn chưa được đồng bộ hóa lại với thân cây. Có thể tạo bản vá toàn cầu từ một cam kết không? Có thể tạo các bản vá "được nhóm" từ một loạt các cam kết không? Nếu có thì làm thế nào? Câu trả lời hay nhất svn diff -rXXX:YYY UR
Trong một số trường hợp, tôi muốn khóa chức năng thay đổi kích thước trong ứng dụng của mình, vì điều này, tôi đã cố gắng liên kết cơ sở dữ liệu thuộc tính và không cho phép thay đổi nó trong một số trường hợp, nhưng không thành công. Có cách nào để làm điều này? Đây là nỗ lực không thành công của tôi: XAML: Vie
Khi tôi có nhiều màn hình được kết nối với máy tính của mình, tôi có thể phát hiện và vẽ chúng dựa trên việc đặt vị trí thành các giá trị thu được từ get(0, 'MonitorPositions') Tuy nhiên, khi tôi ngắt kết nối màn hình trong khi MATLAB đang chạy, Điều này tài sản sẽ không
Chúng tôi có một ứng dụng grails lưu trữ các đối tượng miền khác nhau trong cơ sở dữ liệu grails. Ứng dụng kết nối với cơ sở dữ liệu thứ hai, chạy một số sql thô và hiển thị kết quả dưới dạng bảng. Về cơ bản nó là một máy chủ báo cáo. Chúng tôi sử dụng DataSo
Không thể so sánh các trình vòng lặp từ các vùng chứa khác nhau (xem ví dụ tại đây: https://stackoverflow.com/a/4664519/225186) (hoặc về mặt kỹ thuật thì nó không cần thiết phải có ý nghĩa.) Điều này đặt ra một câu hỏi khác, từ
Tôi gặp tình huống sau: ParentActivity : ParentActivityClass { ý định ý định riêng tư @Override public void onCreate(Bu
Tôi thường nối các phần tử với các hàm bổ sung, ví dụ: $('.myfav').autocomplete(); $('.myfav').datepicker();
Vì vậy, tôi đã sử dụng thư viện tooltipster.js cho chú giải công cụ và thử thay đổi khoảng cách mặc định của chú giải công cụ trên các kích thước màn hình khác nhau. Vì vậy, init mặc định trông như thế này: $(inputTooltipTrigger).tool
Tôi đang làm việc trong môi trường nhúng ARM7. Trình biên dịch tôi đang sử dụng không hỗ trợ đầy đủ chức năng C++. Một tính năng mà nó không hỗ trợ là chuyển đổi kiểu động. Có cách nào để triển khai Dynamic_cast<>() không? Tôi đã sử dụng Google để tìm mã nhưng
Tôi là một lập trình viên xuất sắc, rất giỏi!