迭代平移搬动数组

缪军 2011-11-12 10:43:53
回复这个帖子:
http://topic.csdn.net/u/20111103/12/4ba67e23-33f7-4cde-a6d7-ad7784998d55.html
题目的要求:1.不能使用FCL;2.不能引入新的数组

        static void MoveSubArrayToTheEnd(int[] array, int numberOfElements) {
if(numberOfElements <= 0 || numberOfElements >= array.Length) return;
Move(array, 0, numberOfElements, numberOfElements); }

//迭代平移
static void Move(int[] pArray, int pStart, int pMoveLength, int pOffset) {
int _length = pArray.Length;
if (pStart + pMoveLength >= _length) return;
if(pStart + pMoveLength + pOffset > _length) {
pMoveLength = _length - (pStart + pMoveLength);
}
else {
for(int i = pStart; i < pStart + pMoveLength; i++) {
Swap(ref pArray[i], ref pArray[i + pOffset]);
}
pStart = pStart + pMoveLength;
if(pOffset > pMoveLength) pMoveLength = pOffset - pMoveLength;
pOffset = pMoveLength;
}
Move(pArray, pStart, pMoveLength, pOffset);//迭代
}

//元素交换
static void Swap(ref int a, ref int b) {
a += b;
b = a - b;
a = a - b;
//Count++;//计数
}


以10个自然数为例,从1到9位截取,结果如下(和双重逆序法对比)



不过,当数组的数量是偶数的时候,平移和逆序的计数是一样的

...全文
94 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
q107770540 2011-11-13
  • 打赏
  • 举报
回复
虽然看不懂 感觉很NX
缪军 2011-11-13
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 sbwwkmyd 的回复:]
[/Quote]

双重逆序法的构思确实是很巧妙的
jshi123 2011-11-13
  • 打赏
  • 举报
回复
好多专业术语啊,民间野路子表示听不懂,只知道循环,再贴一遍:
void MoveSubArrayToTheEnd(int[] array, int numberOfElements)
{
int l = array.Length, n = numberOfElements % l, temp = 0;
for (int x = 0, y = 0; y < n * l; x = (x - n + ((y += n) % l + l - 1) / l - 1 + l) % l)
{
int t = array[x];
array[x] = y % l == 0 ? array[(x + n) % l] : temp;
temp = t;
}
}
showjim 2011-11-13
  • 打赏
  • 举报
回复
经本人电脑实测,1亿数据量。
双重逆序表现相当稳定,几次测试后基本稳定在1023ms与1024ms之间。
迭代平移不稳定,与迭代次有很大关系。取多次批量测试的最低平均值为1071ms。以相当低的概率出现过几次101?ms的最低值,最高值甚至出现过14??ms的情况,目测印象中最多的在105?ms附近。

另外,双重逆序可用于并行计算,而迭代平移循环之间存在依赖关系无法并行。
showjim 2011-11-13
  • 打赏
  • 举报
回复
不知道楼主想从这个结果,得到一个什么结论性的东西。
迭代平移比双重逆序的交换次数少,这个是事实。
但是这个并不能说明迭代平移比双重逆序执行效率高。

如果单纯比较数据操作次数的话,直接计算法的操作次数是最少而且确定是n次。
而迭代平移与双重逆序的数据操作次数都接近2n次,因为一次交换相当于两次数据操作。

对于小数据量来说,直接计算法的效率是最高的,应该就上面提到的“编程珠玑”上的那种方案。
但对于大数据量来说,直接计算法比迭代平移或双重逆序的执行效率差很多倍。
为什么呢?因为直接计算法访问内存是跳跃形式的,我们知道内存也有高速缓存。这种关系就相当于内存与虚拟内存之间的关系,显然跳跃形式访问内存是相当低效的。
也就是高速缓存的原因,O(n)的基数排序比O(n*log(n))的归并排序执行效率慢数倍。

我们研究算法,不是讨论它在某个特例上的优势,而是一种稳定的平均效率。
迭代平移与双重逆序,都是顺序访问内存的方式。
迭代平移相对于双重逆序的优势是平均少不到2次数据交换操作,对于大数据量来说2/n真的不算什么。
我们来看看代码逻辑,双重逆序除了交换数据的循环,只有确定的3次逻辑判断。相对于迭代平移,再加上2次数据交换的逻辑判断,一共是5次。
而迭代平移,除了交换数据的循环,理论上有5到3*log(n)次的逻辑判断。在顺序访问内存的情况下,逻辑判断的代价是比较大的。
所以平均来说,双重逆序的执行效率是优于迭代平移的。但是这种优势不到log(n)/n,完全可以忽略不计。

对于执行效率相当的两个算法,一般来说都是优先选择逻辑简单的,易于理解的与实现的。
从逻辑上来说双重逆序更易于理解,并且平均执行效率优良,可以说是非常优秀的算法。
不可否认,迭代平移也很不错。如果将移动的数据单位由CPU字改为byte,这时候双重逆序如果要保持与迭代平移同级的执行效率,逻辑与细节将变得比较复杂,而迭代平移却更易于理解。
threenewbee 2011-11-12
  • 打赏
  • 举报
回复
《编程珠玑》有个很好的办法,就是按照移动数量取模,交换。

110,535

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧