句法糖,恕我直言,通常使程序比从极简主义的原语集编码更易读,更容易理解.我并没有真正看到好的,经过深思熟虑的语法糖的缺点.为什么有些人基本上认为语法糖最多是多余的,最糟糕的是要避免什么?
编辑:我不想命名,但是因为人们问,似乎大多数C++和Java程序员,坦率地说,他们并不关心他们的语言完全没有语法糖.在很多情况下,他们不一定非常喜欢这种语言的其他部分足以使缺糖值得权衡,这是因为他们真的不在乎.此外,Lisp程序员似乎对他们语言的奇怪符号感到骄傲(我不会将其称为语法,因为它在技术上并非如此),尽管在这种情况下,它更容易理解,因为它允许Lisp的元编程工具像它们一样强大.
不使用垃圾收集的明显情况是实时性很强,内存严重受限,并且想要用指针进行操作.有没有其他的,较少讨论的,很好的理由为什么有人更喜欢手动内存管理而不是GC?
给定长度为N的查询字符串Q,以及长度恰好为N的M个序列的列表L,找到L中具有最少错配位置的字符串的最有效算法是什么?例如:
Q = "ABCDEFG";
L = ["ABCCEFG", "AAAAAAA", "TTAGGGT", "ZYXWVUT"];
answer = L.query(Q); # Returns "ABCCEFG"
answer2 = L.query("AAAATAA"); #Returns "AAAAAAA".
Run Code Online (Sandbox Code Playgroud)
显而易见的方法是扫描L中的每个序列,使搜索采用O(M*N).在次线性时间有没有办法做到这一点?我不在乎将L组织到某个数据结构中需要大量的前期成本,因为它会被查询很多次.此外,任意处理捆绑分数也没问题.
编辑:为了澄清,我正在寻找汉明距离.
我鄙视使用过度设计的API,这些API并不简单.尽管如此,我正在为一个开源库设计一个API,我开始觉得我陷入了过度工程陷阱.我当然无法确定,因为当然,我写了一些令人讨厌的东西,所以它的工作原理对我来说比其他任何人都更明显.从开发人员的角度来看,您的API可能过度设计有哪些警告信号?
似乎在C++和D中,静态编译的语言和模板元编程是一种流行的技术,对模板实例化膨胀有很多关注.除了资源非常有限的嵌入式系统外,在我看来,这似乎主要是理论上的问题.在嵌入式领域之外,我还没有听说过一个人能够证明这在实践中是一个问题的例子.
任何人都可以在资源有限的嵌入式系统之外提供一个例子,其中模板实例化膨胀在实践中很重要并且具有可测量的,实际上显着的负面影响吗?
假设您有两个相同长度的列表,L1和L2,N.我们将prodSum定义为:
def prodSum(L1, L2) :
ans = 0
for elem1, elem2 in zip(L1, L2) :
ans += elem1 * elem2
return ans
Run Code Online (Sandbox Code Playgroud)
是否存在一种有效的算法,假设L1被排序,L2的排列数使得prodSum(L1,L2)<某些预先指定的值?
如果它可以简化问题,你可以假设L1和L2都是来自[1,2,...,N]的整数列表.
编辑:Managu的回答让我确信,如果不假设L1和L2是来自[1,2,...,N]的整数列表,这是不可能的.我仍然对采用这种约束的解决方案感兴趣.
我正在为D编程语言开发并行化库.现在我对基本原语(并行foreach,map,reduce和tasks/futures)非常满意,我开始考虑一些更高级别的并行算法.并行化的更明显的候选者之一是排序.
我的第一个问题是,在现实世界中有用的排序算法的并行版本,还是主要是学术性的?如果它们有用,它们在哪里有用?我个人很少在我的工作中使用它们,仅仅是因为我通常使用比单一sort()调用更粗糙的并行度来将100%的所有内核挂起.
其次,对于大型阵列来说,似乎快速排序几乎是令人尴尬的并行,但我不能得到接近线性的加速,我相信我应该得到.对于快速排序,唯一固有的串行部分是第一个分区.我尝试并行化快速排序,在每个分区之后,并行排序两个子阵列.在简化的伪代码中:
// I tweaked this number a bunch. Anything smaller than this and the
// overhead is smaller than the parallelization gains.
const smallestToParallelize = 500;
void quickSort(T)(T[] array) {
if(array.length < someConstant) {
insertionSort(array);
return;
}
size_t pivotPosition = partition(array);
if(array.length >= smallestToParallelize) {
// Sort left subarray in a task pool thread.
auto myTask = taskPool.execute(quickSort(array[0..pivotPosition]));
quickSort(array[pivotPosition + 1..$]);
myTask.workWait();
} else {
// Regular serial quick sort.
quickSort(array[0..pivotPosition]);
quickSort(array[pivotPosition + 1..$]);
}
}
Run Code Online (Sandbox Code Playgroud)
即使对于非常大的阵列,第一个分区所花费的时间可以忽略不计,与纯粹的串行版本的算法相比,我只能在双核上获得大约30%的加速.我猜测瓶颈是共享内存访问.有关如何消除这个瓶颈或瓶颈可能是什么的任何见解?
编辑:我的任务池具有固定数量的线程,等于系统中的核心数减1(因为主线程也起作用).此外,我正在使用的等待类型是工作等待,即如果任务已启动但尚未完成,则线程调用会 …
在像x86这样提供缓存一致性的CPU上,从实际角度来看这有什么用呢?我知道这个想法是在一个核心上完成内存更新,在所有其他核心上立即可见.这是一个有用的属性.但是,如果不用汇编语言编写,就不能过分依赖它,因为编译器可以在寄存器中存储变量赋值,而不会将它们写入内存.这意味着必须采取明确的步骤,以确保在当前线程中可以看到在其他线程中完成的内容.因此,从实际角度来看,缓存一致性实现了什么?
我试图围绕R编程语言的基本概念,我发现很难,因为R面向统计而不是通用编程.我找不到任何类似于指针/引用的东西.如何在R语言中实现链表,搜索树等?
注意:我理解如果你实际上在R中滚动自己的自引用数据结构,可能有更好的方法来完成你想要完成的任务.但是,我相信一个答案将帮助我更好地理解语言的整体结构和概念.
编辑:关于Matt Shotwell的评论,这个问题的关键在于我希望在 R中干净地编写链表和树,而不是用C或其他语言编写的扩展.做它作为一个扩展或通过与解释器的神秘细节混淆失败的目的.
在今天的编程中你看到的最糟糕的(由于流行程度或严重程度)抽象反转的例子是什么?
对于那些不熟悉这个概念的人来说,抽象反转是在高级构造之上实现低级构造.更确切地说,假设你有构造A和B.B是在A之上实现的,但A不会在任何地方暴露.因此,如果你真的需要较低级别的构造A,那么当B首先用A实现时,你最终会在B之上实现A. 见http://en.wikipedia.org/wiki/Abstraction_inversion.
algorithm ×2
d ×2
abstraction ×1
api ×1
api-design ×1
c++ ×1
caching ×1
concurrency ×1
linked-list ×1
low-level ×1
performance ×1
pointers ×1
r ×1
reference ×1
scalability ×1
sorting ×1
statistics ×1
string ×1
templates ×1
x86 ×1