堆栈与整数

时间:2011-09-29 05:25:34

标签: c++ integer stack cryptarithmetic-puzzle

我已经为数据结构课程创建了一个解决Cryptarithmetics的程序。教授建议我们利用由链接节点组成的堆栈来跟踪我们用哪些数字替换哪些字母,但我意识到整数可以做同样的技巧。而不是堆栈{A,1,B,2,C,3,D,4}我可以在1234中保持相同的信息。

但是,我的节目似乎比他给我们的估计要慢得多。有人可以解释为什么堆栈会表现得更有效率吗?我曾经假设,因为我不会一遍又一遍地调用方法(推,弹,顶等),而只是在'解决方案'中添加一个,我的会更快。

这不是一个开放式问题,所以不要关闭它。虽然你可以用不同的方式实现,但我想知道为什么,在C ++的核心,通过堆栈访问数据比在int中存储和通过moding提取具有性能优势。

虽然这是作业,但我实际上并不需要帮助,只是非常好奇和好奇。

谢谢,迫不及待想要学到新东西!

编辑(添加一些代码)

letterAssignments是一个大小为26的int数组。对于像SEND + MORE = MONEY这样的问题,不使用A,因此letterAssignments [0]设置为11.所有使用的字符都初始化为10。 answerNum是一个数字,其数字与唯一字符一样多(在本例中为8位数字)。

int Cryptarithmetic::solve(){
while(!solved()){       
    for(size_t z = 0; z < 26; z++){
        if(letterAssignments[z] != 11) letterAssignments[z] = 10;
    }
    if(answerNum < 1) return NULL;
    size_t curAns = answerNum;

    for(int i = 0; i < numDigits; i++){ 
        if(nextUnassigned() != '$') {
            size_t nextAssign = curAns % 10;
            if(isAssigned(nextAssign)){
                    answerNum--;
                    continue;
                }
            assign(nextUnassigned(), nextAssign);
            curAns /= 10;
        }
    }
    answerNum--;
}
return answerNum;
}

如果你想看到它们,可以使用两种辅助方法:

char Cryptarithmetic::nextUnassigned(){ 
char nextUnassigned = '$';
for(int i = 0; i < 26; i++) {
    if(letterAssignments[i] == 10) return ('A' + i);
}
}

void Cryptarithmetic::assign(char letter, size_t val){
assert('A' <= letter && letter <= 'Z');  // valid letter
assert(letterAssignments[letter-'A'] != 11); // has this letter
assert(!isAssigned(val)); // not already assigned.
letterAssignments[letter-'A'] = val;
}

4 个答案:

答案 0 :(得分:1)

从事物的外观来看,你在这里做事的方式是非常无效的。

作为一般规则,尝试使用最少量的for循环,因为每个循环都会大大减慢您的实现。

例如,如果我们删除所有其他代码,您的程序看起来像

while(thing) {
  for(z < 26) {

  }
  for(i < numDigits) {
    for(i < 26) {

    }
    for(i < 26) {

    }
  }
}

这意味着你正在做的每个while循环((26 + 26)* numDigits)+26循环操作。假设isAssigned()不使用循环。

想要你想要:

while(thing) {
  for(i < numDigits) {
  }
}

我确信可以更改代码。 这就是为什么使用整数数组的实现要慢于使用不使用for(i < 26)循环的堆栈的实现(我假设)。

在对原始问题的回答中,存储一个整数数组总是比你想出的任何结构更快,因为分配内存,调用函数等涉及更多的开销。

但与所有事情一样,实施是慢速程序和快速程序之间的关键区别。

答案 1 :(得分:0)

mod函数使用的 div 指令非常昂贵。将它用于您的目的可能比一个好的堆栈实现效率低。这是一个指令时间表:http://gmplib.org/~tege/x86-timing.pdf

您还应该为基于int的堆栈编写单元测试,以确保它按预期工作。

答案 2 :(得分:0)

问题在于,通过计算你也在考虑重复,当问题可能要求为每个不同的字母分配一个不同的数字,以便数字方程成立。

例如,对于四个字母,您正在测试10*10*10*10=10000字母 - >数字映射而不是10*9*8*7=5040(字母数量越大,两个数字之间的比例越大。 )。

答案 3 :(得分:0)

编程实际上是时间交易记忆,反之亦然。 在这里,您将数据打包为整数。你节省了时间但是时间很长。

速度当然取决于堆栈的实现。 C ++是带有类的C.如果你不使用类,它基本上是C(和C一样快)。

const int stack_size = 26;

struct Stack
{
  int _data[stack_size];
  int _stack_p;
  Stack()
  :_stack_size(0)
  {}
  inline void push(int val)
  {
     assert(_stack_p < stack_size); // this won't be overhead 
                                    // unless you compile debug version(-DNDEBUG) 
     _data[_stack_p] = val;
  }

  inline int pop()
  {
    assert(_stack_p > 0);       // same thing. assert is very useful for tracing bugs
    return _data[--_stack_p];  // good hint for RVO
  }

  inline int size()
  {
    return _stack_p;
  }

  inline int val(int i)
  {
    assert(i > 0 && i < _stack_p);      
    return _data[i];
  }
}

没有像vtbp这样的开销。 pop()和push()也非常简单,因此它们将被内联,因此没有函数调用的开销。使用int作为堆栈元素也有利于速度,因为int保证最适合处理器的大小(不需要对齐等)。