在c++中为嵌入式系统排序有效和无效的数字数组

Sorting an array of valid and invalid numbers in c++ for an embedded system

本文关键字:无效 数字 数组 有效 排序 c++ 嵌入式 系统      更新时间:2023-10-16

我正在用c++写一个程序,将与Windows Embedded Compact 7一起使用。我听说在编写嵌入式代码时最好不要动态分配数组。我将跟踪0到50个对象,所以我最初分配了50个对象。

Object objectList[50];
int activeObjectIndex[50];
static const int INVALID_INDEX = -1;
int activeObjectCount=0;

activeObjectCount告诉我实际使用了多少对象,activeObjectIndex告诉我使用了哪些对象。如果第0、第7和第10个对象被使用,我想要activeObjectIndex = [0,7,10,-1,-1,-1,...,-1];activeObjectCount=3;当不同的对象变为活动或非活动时,我希望activeObjectIndex列表保持有序。

目前我只是排序的activeObjectIndex在每个循环结束时的值可能会改变。

首先,在嵌入式系统中,是否有比我正在做的更好的方法来跟踪对象(可能是活动的,也可能不是活动的)?如果没有,是否有一个算法,我可以使用保持对象排序每次我添加或删除一个活动对象?或者我应该周期性地做一个冒泡排序或者别的什么来保持它们的顺序?

您遇到了一个很难的问题,答案需要对您的系统有相当多的了解。没有这些知识,我所能给出的答案都是不完整的。然而,15年的嵌入式设计经验教会了我以下几点:

  1. 你是正确的,你通常想要在运行时分配对象。预先分配所有对象,并将它们移动到活动/非活动队列。
  2. 把东西分类通常是困难的。也许你不需要。你没有提到它,但我敢打赌你真的只需要保持你的对象在"使用"answers"自由"池,你正在使用索引来快速查找/删除对象。

我提出以下解决方案。将对象更改为以下内容:

class Object {
  Object *mNext, *mPrevious;
public:
  Object() : mNext(this), mPrevious(this) { /* etc. */ }
  void insertAfterInList(Object *p2) {
    mNext->mPrev = p2;
    p2->mNext = mNext;
    mNext = p2;
    p2->mPrev = this;
  }
  void removeFromList() {
    mPrev->mNext = mNext;
    mNext->mPrev = mPrev;
    mNext = mPrev = this;
  }
  Object* getNext() {
    return mNext;
  }
  bool hasObjects() {
    return mNext != this;
  }
};

和使用你的对象:

#define NUM_OBJECTS (50)
Object gObjects[NUM_OBJECTS], gFree, gUsed;
void InitObjects() {
  for(int i = 0; i < NUM_OBJECTS; ++i) {
    gFree.insertAfter(&mObjects[i]);
  }
}
Object* GetNewObject() {
  assert(mFree.hasObjects());
  Object obj = mFree->getNext();
  obj->removeFromList();
  gUsed.insertAfter(obj);
  return obj;
}
void ReleaseObject(Object *obj) {
  obj->removeFromList();
  mFree.insertAfter(obj);
}

编辑修复一个小故障。应该现在工作,虽然没有测试。:)

std::vector的开销非常小。您可能遇到的问题是,动态调整大小将分配比所需更多的内存。然而,由于您有50个元素,这应该不是一个问题。试一试,只有当你看到强烈的影响时才改变它。

如果你不能/不想从std::vector中删除未使用的对象,你可以在你的Object中添加一个布尔值来指示它是否处于活动状态。这不会比使用activeObjectIndex需要更多的内存(甚至可能更少,取决于对齐问题)。

要用布尔值对数据进行排序(最后不活动),编写一个函数:

bool compare(const Object & a, const Object & b) {
    if(a.active && !b.active) return true;
    else return false;
}
std::sort(objectList,objectList + 50, &compare); // if you use an array
std::sort(objectList.begin(),objectList.end(), &compare); // if you use std::vector

如果你想用activeObjectIndex排序,那将会更复杂。如果你想使用一个总是有序的结构,使用std::set。然而,它将需要更多的内存(但对于50个元素,这不会是一个问题)。

理想情况下,实现以下功能:

bool operator<(const Object & a, const Object & b) {
    if(a.active && !b.active) return true;
    else return false;
}

这将允许直接使用std::sort(objectList.begin(), objectList.end())或声明一个std::set保持排序

跟踪活动/非活动的一种方法是将活动对象放在双链表中。当一个对象从非活动状态变为活动状态时,将其添加到列表中,而从活动状态变为非活动状态时,将其从列表中删除。您可以将这些添加到对象

Object * next, * prev;

如果不允许动态内存分配,我将使用简单的c-array或std::array和指向last+1对象的索引。对象总是保持有序。

加法是通过将新对象插入到已排序列表的正确位置来完成的。要找到插入位置,可以使用lower_boundfind_if。对于50个元素,秒可能会更快。移除也是类似的。

您不应该担心列表排序,因为编写一个方法来搜索索引列表中的活动索引将是O(N),并且,在您的特殊情况下,平销到O(1),因为您的数组似乎足够小,可以进行这个小小的额外验证。

你可以维持最后一个被检查元素的索引,直到它达到极限:

unsigned int next(const unsigned int& last) {
    for (unsigned int i = last + 1; i < MAX_ARRAY_SIZE; i++) {
        if (activeObjectIndex[i] != -1) {
            return i;
        }
    }
    return -1;
}

然而,如果你真的想有一个侧索引,你可以简单地将数组的大小加倍,创建一个双链表的元素:

activeObjectIndex[MAX_ARRAY_SIZE * 3] = {-1};
activeObjectIndex[i] = "element id";
activeObjectIndex[i + 1] = "position of the previous element";
activeObjectIndex[i + 2] = "position of the next element";