Matlab 位排序算法中存储管理的改进
从《编程珍珠》一书中,我阅读了有关位排序算法的信息,下面是它在matlab中的简单示例Matlab 位排序算法中存储管理的改进,matlab,sorting,memory-management,Matlab,Sorting,Memory Management,从《编程珍珠》一书中,我阅读了有关位排序算法的信息,下面是它在matlab中的简单示例 function result=bit_sort(A) % given array of integers, sort element of A using bit sort max_element=max(A); % find maximum element of A b=zeros(max_element,1); result=zeros(size(A)); n=length(A); for ii=1:
function result=bit_sort(A)
% given array of integers, sort element of A using bit sort
max_element=max(A); % find maximum element of A
b=zeros(max_element,1);
result=zeros(size(A));
n=length(A);
for ii=1:n
b(A(ii))=1;
end
k=1;
for ii=1:max_element
if b(ii)==1
result(k)=ii;
k=k+1;
end
end
end
这里还有一个很好的例子
A=[2 1 3 6 5 4 9 7];
>> result=bit_sort(A)
result =
1 2 3 4 5 6 7 9
另一个例子
a=[2 1 4 100];
>> result=bit_sort(a)
result =
1 2 4 100
代码运行良好,但我有一个不同的问题:在这行的代码声明中
max_element=max(A); % find maximum element of A
b=zeros(max_element,1);
占用内存的另一部分,在某些情况下可能不需要,例如,当我有4个元素:1 2 4 100时,如何有效地进行数组声明,以便实现两个条件:1。有效的内存管理2.保持算法的恒定速度?提前感谢这是同一代码的矢量化版本
function result=bit_sort_vecorized(A)
% vectorized version
b(A(1:end))=1;
result=zeros(size(A));
n=length(b);
k=1;
for ii=1:n
if b(ii)==1
result(k)=ii;
k=k+1;
end
end
end
A=[2 1 3 6 5 4 9 7];
>> result=bit_sort_vecorized(A)
result =
1 2 3 4 5 6 7 9
1) 首先,您可以进一步使用矢量化:
替换此代码
k=1;
for ii=1:n
if b(ii)==1
result(k)=ii;
k=k+1;
end
end
关于这一点:
result = find( b == 1);
2) 关于计算速度:
我将这个循环用于b=randi(10,1100000)
,得到这个循环:
result = find( b == 1);
使用循环经过的时间为0.019176秒。
避免循环--经过的时间为0.015142秒。
因此没有真正显著的优势 创建零和一的初始数组或定位
1
的位置不需要循环。相反,我们可以使用ismember
和find
生成结果
function result = bit_sort(x)
result = find(ismember(1:max(x), x));
end
解释
ismember
检查第一个输入中的每个条目是否存在于第二个输入中。在您的情况下,因为我们需要一个数组,其中每个数字的条目都在1和max(x)
之间,如果值在x
和false
中,那么我们希望值为true
,否则我们可以这样做
tmp = ismember(1:max(x), x)
% 1 1 1 1 1 1 1 0 1
然后我们可以使用find
获取上述数组中每个1的位置
find(tmp)
% 1 2 3 4 5 6 7 9
其他一些备选方案
与使用ismember
不同,您可以依赖这样一个事实:在MATLAB中,如果您使用索引分配给空数组,任何未指定的索引都将接收默认值0
,因此我们可以使用
tmp(x) = true; % Create a logical array
result = find(tmp); % Again, use find to get the indices
此解决方案的好处是,您不必创建数组
1:max(x)
,因此可以节省内存。另外,tmp
是一个逻辑
数组,而不是一个double
,因此它比您的示例中的b
占用的空间少8倍。为了完整性起见,下面是一个使用实际位向量的实现。位向量的大小为ceil(max_element/8)
bytes,约为双数组大小的1/64或逻辑数组大小的1/8。它也可能比其他实现慢。它仍然是O(n),但常数无疑增加了
function result = bit_sort(A)
% given array of integers, sort element of A using bit sort
% integers must be strictly positive
max_element = max(A); % find maximum element of A
bitvec_size = ceil(max_element/8); % 8 bits per uint8
b = zeros(bitvec_size, 1, 'uint8');
result = zeros(size(A));
n = length(A);
for ii=1:n
current_num = A(ii) - 1; % account for 1-based indexing
byte_num = idivide(current_num, 8) + 1; % find byte for our value
% set bit # mod(n, 8) in byte found above
% add one again for 1-based bit indexing
b(byte_num) = bitset(b(byte_num), mod(current_num, 8) + 1);
end
k = 1;
for bytenum = 1:bitvec_size
for bitnum = 1:8
if bitget(b(bytenum), bitnum)
result(k) = (bytenum-1)*8 + bitnum; % bitnum = bitnum - 1 + 1
% I love 1-based indexing
k = k + 1;
end
end
end
end
对于输入数组中的每个值,使用整数除法将值除以8,从而将字节数(索引)查找到向量中。然后设置mod 8值在该字节中找到的位。在每个步骤中,都需要调整基于1的索引。有趣的是,您可以使用ind2sub
来查找索引和位号,但这将更加神秘
您可以通过多种不同的方式实现相同的功能,使用bit\u或和bit shift
,也可以使用bi2de
进行解码。我不知道它们是否会更快,但这里的主要目标是展示一种减少位向量b
内存使用的方法
如果知道最小数组值远大于1,则可以进行另一个较小的优化,即使用最小值作为数组的基础。只有当最小值约为最大值的一半(或更多)时,这才有意义,在这种情况下,您至少可以将位向量的大小减半。如果A的元素数远小于最大值,则更有效的方法是使用稀疏矩阵:
find(sparse(A,1,A));
或更有效:
find(sparse(A,1,true));
只运行一次代码并不是一种很好的评测方式,尤其是对于JIT编译器。不管怎么说,你的计时显示相对速度提高了近25%。这可能真的很重要。感谢大家对存储的帮助?我的意思是,这种改变会提高存储利用率吗?@datodatuashvili,正如我在回答的最后一部分所说,如果你采用我的方法,它使用的逻辑数组比你正在使用的双数组小。上帝保佑你,明天我会详细介绍,它会排序数组吗?