我有两个稀疏矢量X和Y,想要得到O(m + n)中的点积,其中m和n是X和Y中非零元素的数量。我能想到的唯一方法是从向量X中选取每个元素并遍历向量Y以查找是否存在具有相同索引的元素。但这需要O(m * n)。我将矢量实现为链表,每个节点都有一个元素。
答案 0 :(得分:6)
如果您的向量存储为元组的链表,并且每个元组包含索引和非零元素的值并按索引排序,则可以执行此操作。
通过从矢量中选择下一个元素来迭代这两个矢量,您在较低的索引处。如果索引相同,则将元素相乘并存储结果。
重复直到一个列表到达结尾。
由于每个列表中每个非零元素都有一步,因此复杂度为O(m + n)。
脚注:数据结构不必是链表,但必须提供O(1)方式来访问下一个非0元素及其索引。
答案 1 :(得分:0)
假设您的非零元素在两个向量中按坐标索引排序,则通过 merge 算法实现。这是计算机科学中的标准算法,它将两个排序的序列合并为一个排序的序列,并且它在 O(M + N)中工作。
有两种方法可以做到这一点。第一个是检查合并中的相同元素。这确实是最好的方式。
第二种方法是首先合并,然后检查等于(它们必须连续):
std::pair<int, double> vecA[n], vecB[m], vecBoth[n+m];
std::merge(vecA, vecA+n, vecB, vecB+m, vecBoth);
double dotP = 0.0;
for (int i = 0; i+1 < n+m; i++)
if (vecBoth[i].first == vecBoth[i+1].first)
dotP += vecBoth[i].second * vecBoth[i+1].second;
std::merge的复杂性是 O(M + N)。
上面的例子假设数据存储在数组中(这是稀疏向量和矩阵的最佳选择)。如果您想使用链接列表,还可以在 O(M + N)时间内执行合并,请参阅this question。
即使您的列表未排序,您仍然可以在 O(M + N)时间内执行点积。我们的想法是首先将 A 的所有元素放入哈希表中,然后遍历 B 的元素,看看是否存在具有相同索引的哈希中的元素。
如果索引非常大(例如超过百万),那么也许您应该使用非平凡的哈希函数。但是,如果您的索引相当小,那么您可以避免使用哈希函数。只需使用大于矢量维度的数组。为了快速清除这个数组,你可以使用“代数”这个技巧。
//global data! must be threadlocal in case of concurrent access
double elemsTable[1<<20];
int whenUsed[1<<20] = {0};
int usedGeneration = 0;
double CalcDotProduct(std::pair<int, double> vecA[n], vecB[m]) {
usedGeneration++; //clear used array in O(1)
for (int i = 0; i < n; i++) {
elemsTable[vecA[i].first] = vecA[i].second;
whenUsed[vecA[i].first] = usedGeneration;
}
double dotP = 0.0;
for (int i = 0; i < m; i++)
if (whenUsed[vecB[i].first] == usedGeneration)
dotP += elemsTable[vecB[i].first] * vecB[i].second;
return dotP;
}
请注意,您可能需要清除每十亿点产品whenUsed
一次。
答案 2 :(得分:0)
$(document).ready(function(){
var dataSet = '{"status":"success","data":[{"key":"Open","values":[[1512432000,55.65],[1512518400,54.45],[1512604800,53.05],[1512691200,56.4],[1512950400,54.65],[1513036800,55],[1513123200,53.9],[1513209600,56],[1513296000,55.9],[1513555200,56.25]]},{"key":"High","values":[[1512432000,55.65],[1512518400,55],[1512604800,57.95],[1512691200,57],[1512950400,55.5],[1513036800,55.4],[1513123200,58.9],[1513209600,56.5],[1513296000,58.5],[1513555200,57.75]]},{"key":"Low","values":[[1512432000,53.65],[1512518400,53.1],[1512604800,53.05],[1512691200,54.1],[1512950400,54.65],[1513036800,53.7],[1513123200,53],[1513209600,54],[1513296000,55.1],[1513555200,52.5]]},{"key":"Close","values":[[1512432000,54.55],[1512518400,53.6],[1512604800,55.9],[1512691200,54.65],[1512950400,54.9],[1513036800,54.1],[1513123200,55.65],[1513209600,54.45],[1513296000,56.5],[1513555200,55.65]]}]}';
var n = nv.addGraph(function () {
var chart = nv.models.cumulativeLineChart()
.x(function (d) {
return d[0]
})
.y(function (d) {
return d[1]
})
.color(d3.scale.category10().range())
.useInteractiveGuideline(true)
;
chart.xAxis
.tickFormat(function (d) {
return d3.time.format('%x')(new Date(d))
})
chart.yAxis
.tickFormat(d3.format(''));
d3.select('#chart1 svg')
.datum(JSON.parse(dataSet)['data'])
.call(chart);
return chart;
});
});