Matlab deque实现
一直以来数据结构这块是MATLAB的弱项,虽然其不支持指针,但是一些比较简单的数据结果还是能胜任的。
之前的工作中,有需要将C++代码移植到MATLAB上的需求,其中就使用到了deque,由于当时时间比较紧迫就没有多考虑,使用ring buffer实现了,但回来仔细想想,其实MATLAB也可以支持动态数组,所以也尝试一下使用动态数组来实现deque。代码比较简单,直接贴出,使用类来实现的。
classdef Deque < handle
properties (Constant)
MaxQueueSize = 1000
properties
methods
function obj = Deque()
coder.inline('never')
obj.data = [];
obj.size = 0;
function pushBack(this,u)
coder.inline('never')
this.data = [this.data u];
this.size = this.size+1;
function pushFront(this,u)
coder.inline('never')
this.data = [u this.data];
this.size = this.size+1;
function [err,y] = popBack(this)
coder.inline('never')
err = true;
y = 0;
if this.size <= 0
return;
y = this.data(end);
this.data = this.data(1:end-1);
this.size = this.size-1;
err = false;
function [err,y] = popFront(this)
coder.inline('never')
err = true;
y = 0;
if this.size <= 0
return;
y = this.data(1);
this.data = this.data(2:end);
this.size = this.size-1;
err = false;
function y = isEmpty(this)
coder.inline('never')
y = (this.size == 0);
function clearData(this)
coder.inline('never')
this.data = [];
this.size = 0;
测试代码也贴出
function xDeque()
q = Deque();
for i = 1:Deque.MaxQueueSize
q.pushBack(1);
for i = 1:100
[err,y] = q.popFront();
for i = 1:100
q.pushFront(2);
q.clearData();
y = q.isEmpty();
for i = 1:Deque.MaxQueueSize
q.pushFront(3);
for i = 1:100
[err,y] = q.popBack();
for i = 1:100
q.pushBack(4);
q.clearData();
end
代码非常直接,直接使用MATLAB的index特性,也非常直观。coder.inline('never')保证每一个method都能被生成一个函数而不是内联函数,但是这会报错,错误如下,但是此时可变大小已经打开。
function obj = Deque()
coder.inline('never')
data = [];
coder.varsize('data',[1,Deque.MaxQueueSize])
obj.data = data;
obj.size = 0;
end
通过上面的代码指定data为可变大小,最大大小为Deque.MaxQueueSize。可以稍微看一下MATLAB生成的代码其实是重新分配空间然后重新拷贝,这其实不太好。
void Deque_pushFront(Deque *this, double u)
emxArray_real_T *b_u;
int i5;
int loop_ub;
emxInit_real_T(&b_u, 2);
i5 = b_u->size[0] * b_u->size[1];
b_u->size[0] = 1;
b_u->size[1] = 1 + this->data->size[1];
emxEnsureCapacity_real_T(b_u, i5);
b_u->data[0] = u;
loop_ub = this->data->size[1];
for (i5 = 0; i5 < loop_ub; i5++) {
b_u->data[i5 + 1] = this->data->data[i5];
i5 = this->data->size[0] * this->data->size[1];
this->data->size[0] = 1;
this->data->size[1] = b_u->size[1];
emxEnsureCapacity_real_T(this->data, i5);
loop_ub = b_u->size[0] * b_u->size[1];
for (i5 = 0; i5 < loop_ub; i5++) {
this->data->data[i5] = b_u->data[i5];
emxFree_real_T(&b_u);
this->size++;
}
这里也放一下使用ring buffer完成同样功能的代码,不需要动态分配空间 。特别说明一下,obj.head =1;obj.tail = lDeque.MaxQueueSize; 这两行代码给head和tail初值,这样做可以保证对空的deque中push front和push back能做到和非空时候一样,无需特殊处理空deque的情况。如果deque的size非0,head指向第一个元素tail指向最后一个元素。
classdef lDeque < handle
properties (Constant)
MaxQueueSize = 1000
properties
methods
function obj = lDeque()
coder.inline('never')
obj.data = zeros(1,lDeque.MaxQueueSize);
obj.head = 1;
obj.tail = lDeque.MaxQueueSize;
obj.size = 0;
function err = pushBack(this,u)
coder.inline('never')
err = true;
if this.size == lDeque.MaxQueueSize
return
xtail = this.tail+1;
if xtail > lDeque.MaxQueueSize
xtail = xtail-lDeque.MaxQueueSize;
this.data(xtail) = u;
this.tail = xtail;
this.size = this.size+1;
err = false;
function err = pushFront(this,u)
coder.inline('never')
err = true;
if this.size == lDeque.MaxQueueSize
return
xhead = this.head-1;
if xhead < 1
xhead = xhead+lDeque.MaxQueueSize;
this.data(xhead) = u;
this.head = xhead;
this.size = this.size+1;
err = false;
function [err,y] = popBack(this)
coder.inline('never')
err = true;
y = 0;
if this.size <= 0
return
elseif this.size == 1
y = this.data(this.tail);
this.clearData();
xtail = this.tail;
y = this.data(xtail);
xtail = xtail-1;
if xtail < 1
xtail = xtail+lDeque.MaxQueueSize;
this.tail = xtail;
this.size = this.size-1;
err = false;
function [err,y] = popFront(this)
coder.inline('never')
err = true;
y = 0;
if this.size <= 0
return
elseif this.size == 1
y = this.data(this.head);
this.clearData();
xhead = this.head;
y = this.data(xhead);
xhead = xhead+1;
if xhead > lDeque.MaxQueueSize
xhead = xhead-lDeque.MaxQueueSize;
this.head = xhead;
this.size = this.size-1;
err = false;
function y = isEmpty(this)
y = (this.size == 0);
function clearData(this)
coder.inline('never')
this.data = zeros(1,lDeque.MaxQueueSize);
this.head = 1;
this.tail = lDeque.MaxQueueSize;
this.size = 0;
end
通过ring buffer的方式生成的代码非常简洁,执行效率也很高,下面附上push front的代码,请读者和使用动态数组的方式对比一下。
void lDeque_pushFront(lDeque *this, double u)
double xhead;
if (!(this->size == 1000.0)) {
xhead = this->head - 1.0;
if (xhead < 1.0) {
xhead += 1000.0;