最近做东西的时候出现这么一个问题,看起来很简单的:
#define LARGE_SIZE 1024
#define ELEMENT_NUM 5
class CItem
{
public:
TCHAR cID;
BYTE data[LARGE_SIZE];
};
CItem data[ELEMENT_NUM];
INT reposition[ELEMENT_NUM] = {4,2,0,3,1};
要求,根据repositon的内容调整data的内容,如上,把原来下标4的元素调到0,把原来下标2的元素调到1。
写个算法,复杂度为O(n),还要尽量节省空间,因为LARGE_SIZE可以很大,并且ELEMENT_NUM可能远远不止5个元素。
马上能想到的方法就是:
INT i;
CItem *pToHandle = new CItem[ELEMENT_NUM];
memcpy(pToHandle, data, sizeof(data));
for(i=0; i<ELEMENT_NUM; i++)
{
data[i] = pToHandle[reposition[i]];
}
delete[] pToHandle;
但这不太符合节省空间的原则,有可能在一个嵌入式平台中,new操作就会失败。
问题看起来是简单,但却耗费了我不少时间,才写出这么一个算法,我直接贴上全部代码:
#include "stdafx.h"
#include <Windows.h>
#define LARGE_SIZE 1024
class CItem
{
public:
TCHAR cID;
BYTE data[LARGE_SIZE];
};
#define ELEMENT_NUM 10
int _tmain(int argc, _TCHAR* argv[])
{
//Data to test
CItem allData[ELEMENT_NUM];
INT i;
for (i=0; i<ELEMENT_NUM; i++)
{
allData[i].cID = 'A' + i;
}
INT position[ELEMENT_NUM] = {5, 1, 4, 3, 6, 9, 7, 2, 0, 8};
//The result be F B E D G J H C A I
for (i=0; i<ELEMENT_NUM; i++)
{
CItem swapItem;
if (position[i]==i)
continue;
swapItem = allData[i];
INT iSeek = i;
do
{
INT iToSeekNext = position[iSeek];
allData[iSeek] = allData[iToSeekNext];
position[iSeek] = iSeek;
iSeek = iToSeekNext;
} while (position[iSeek]!=i);
allData[iSeek] = swapItem;
position[iSeek] = iSeek;
}
for (i=0; i<ELEMENT_NUM; i++)
{
_tprintf(TEXT("%c "), allData[i].cID);
}
_tprintf(TEXT("\n"));
return 0;
}
看起来写得稍微有些乱,而且明显用了两层迭代,按道理说算法复杂度应该为O(n2)了,但再仔细分析代码后发觉:需要调整位置的元素,只需要移动一次,而整个遍历过程并不会出现重复遍历的情况。因此其实际复杂度应该为O(n),已经是最高效了,看看还有没别的办法。