我的目标是将我的O(n ^ 2)算法减少为O(n),因为它是我的Array2D类中的常见算法。 Array2D拥有一个T类型的多维数组。我看到的一个常见问题是使用双嵌套for循环遍历数组,这取决于大小。
正如你所看到的,我在这里将我的双嵌套for循环简化为单个for循环。我执行它时运行正常。速度肯定有所改善。有没有其他方法可以提高这个成员函数的速度?我希望将此算法用作我在多维数组上具有类似操作的其他成员函数的模型。
/// <summary>
/// Fills all items within the array with a value.
/// </summary>
/// <param name="ob">The object to insert.</param>
void fill(const T &ob)
{
if (m_array == NULL)
return;
//for (int y = 0; y < m_height; y++)
//{
// for (int x = 0; x < m_width; x++)
// {
// get(x, y) = ob;
// }
//}
int size = m_width * m_height;
int y = 0;
int x = 0;
for (int i = 0; i < size; i++)
{
get(x, y) = ob;
x++;
if (x >= m_width)
{
x = 0;
y++;
}
}
}
答案 0 :(得分:4)
确保内存中的内容是连续的,因为缓存行为可能会占用任何只执行简单操作的代码的运行时。
例如,不要使用它:
int* a[10];
for(int i=0;i<10;i++)
a[i] = new int[10];
//Also not this
std::vector< std::vector<int> > a(std::vector<int>(10),10);
使用此:
int a[100];
//or
std::vector<int> a(100);
现在,如果您需要使用2D访问:
for(int y=0;y<HEIGHT;y++)
for(int x=0;x<WIDTH;x++)
a[y*WIDTH+x];
对紧密循环使用1D访问,不依赖于邻居知识的全数组操作,或者需要存储索引的情况:
for(int i=0;i<HEIGHT*WIDTH;i++)
a[i];
请注意,在上述两个循环中,两种情况下触摸的项目数均为HEIGHT*WIDTH
。虽然它可能出现,其时间复杂度为O(N^2)
而另一个O(n)
,但显然已完成的工作量为HEIGHT*WIDTH
两种情况。最好将N
视为操作所触及的项目总数,而不是它们被触摸的方式的属性。
答案 1 :(得分:1)
有时您可以通过计算循环来计算Big O,但并非总是如此。
from datetime import datetime
from collections import defaultdict
from twisted.web import resource, server
from twisted.internet.task import react
from twisted.internet import reactor
from twisted.internet.defer import DeferredList, Deferred
from twisted.internet.endpoints import TCP4ServerEndpoint
from autobahn.twisted.websocket import WebSocketServerProtocol, WebSocketServerFactory
from schema import schema
import json
import os
import sys
from twisted.python import log
def log(msg):
print("{}: {}".format(str(datetime.now()), msg))
class WsProtocol(WebSocketServerProtocol):
"""Dummy websocket protocol"""
def __init__(self, topics):
super(WsProtocol, self).__init__()
self.topics = topics
self.subscribed_topic = None
log("WS protocol init")
def onConnect(self, request):
print("WebSocket connected.")
def onOpen(self):
print("WebSocket connection open.")
def onMessage(self, payload, isBinary):
log(payload)
self.sendMessage("Message received")
def onClose(self, wasClean, code, reason):
print("WebSocket connection closed: {}".format(reason))
def connectionLost(self, reason):
WebSocketServerProtocol.connectionLost(self, reason)
log("Connection closed: Reason is {}".format(reason))
class WsProtocolFactory(WebSocketServerFactory):
def __init__(self):
super(WsProtocolFactory, self).__init__()
self.topics = defaultdict(set)
def buildProtocol(self, *args, **kwargs):
protocol = WsProtocol(self.topics)
protocol.factory = self
return protocol
def setup_protocols(reactor):
factories = {
WsProtocolFactory: 9001,
}
for factory, port in factories.items():
endpoint = TCP4ServerEndpoint(reactor, port)
endpoint.listen(factory())
log("Bound port {} to protocol {}".format(str(port), factory))
return Deferred()
if __name__ == '__main__':
react(setup_protocols)
大O是&#34; for (int m = 0; m < M; m++)
{
for (int n = 0; n < N; n++)
{
doStuff();
}
}
执行了多少次?&#34;使用上面的嵌套循环,它将执行MxN次。
如果我们将其展平为1维
doStuff
我们现在有一个循环执行MxN次。一圈。没有改善。
如果我们展开循环或玩Duff's device
之类的游戏for (int i = 0; i < M * N; i++)
{
doStuff();
}
我们仍然有for (int i = 0; i < M * N; i += N)
{
doStuff(); // 0
doStuff(); // 1
....
doStuff(); // N-1
}
的MxN来电。有些日子你不能用Big O赢。如果你必须在数组中的每个元素上调用doStuff
,无论多少维度,你都无法减少Big O.但是如果你能找到更智能的算法这可以让你避免拨打doStuff
...这就是你要找的东西。
对于Big O,无论如何。有时候你会发现那些有着差劲或者更糟糕的大O的东西,但它的表现要好得多。其中一个classic examples of this is std::vector
vs std::list
.由于在现代CPU中进行缓存和预测,doStuff
获得了对Big O的服从失败的胜利。
旁注(因为我经常自己对此进行自我调整)O(n)意味着如果你加倍,你的工作量增加一倍。这就是O(n)与O(1,000,000 n)相同的原因。 O(n 2 )意味着如果你加倍,那么你可以完成2 2 倍的工作。如果您对算法感到困惑,请将计数器放入您关注的操作中,并使用各种N进行一批测试运行。然后检查那些Ns的计数器之间的关系。