Python 最近邻计算中的错误条件检查?

Python 最近邻计算中的错误条件检查?,python,traveling-salesman,Python,Traveling Salesman,我试着写一个函数,从列出的第一个城市开始,用这个函数计算旅行推销员通过城市列表的大致路线。但是,每次运行它时,我都会得到索引器:列表索引超出范围 在调试错误时,我发现index的值在一次循环迭代到下一次循环迭代时保持不变,而不是改变。当需要追加时,代码会检查是否处于状态;由于它是False,它将1添加到i并移动到循环的下一个迭代。一旦它达到比数组中存在的数字更高的值,就会给出错误 因此,我的问题是,如果不在块中,为什么执行不输入第一个?代码似乎忽略了它 对于我的实际问题,我正在阅读317个城市的

我试着写一个函数,从列出的第一个城市开始,用这个函数计算旅行推销员通过城市列表的大致路线。但是,每次运行它时,我都会得到
索引器:列表索引超出范围

在调试错误时,我发现
index
的值在一次循环迭代到下一次循环迭代时保持不变,而不是改变。当需要追加时,代码会检查
是否处于
状态;由于它是
False
,它将
1
添加到
i
并移动到循环的下一个迭代。一旦它达到比数组中存在的数字更高的值,就会给出错误

因此,我的问题是,如果不在
块中,为什么执行不输入第一个
?代码似乎忽略了它

对于我的实际问题,我正在阅读317个城市的文件,每个城市都有一个索引和两个坐标。以下是测试城市的简短样本列表:

Nodelist=[
(1, 63, 71),
(2, 94, 71),
(3, 142, 370),
(4, 173, 1276),
(5, 205, 1213),
(6, 213, 69),
(7, 244, 69),
(8, 276, 630),
(9, 283, 732),
(10, 362, 69),
]
以下是函数的代码:

def最近(节点列表、距离、索引):
时间\计算=时间。时间()
Newarray=[]
追加(节点列表[0])
对于范围(0,len(节点列表))中的i:
对于范围(1,len(节点列表))中的j:
如果(节点列表[j]不在新数组中):
DisEquation=math.sqrt(pow(Nodelist[j][1]-Newarray[i][1,2)+pow(Nodelist[j][2]-Newarray[i][2,2))
如果距离=0:
距离=不平衡
如果距离>不平衡:
指数=j
距离=不平衡
如果(节点列表[索引]不在新数组中):
追加(节点列表[索引])
距离=0
打印(time.time()-时间计算)
返回新数组
调用它的代码:

NearestMethodArr=最近的(城市、b、索引)
打印(最接近的方法arr)
打印(len(最接近的方法arr))
print
语句应产生:

[(1,63,71)、(2,94,71)、(6,213,69)、(7,244,69)、(10,362,69)、(3,142,370)、(8,276,630)、(9,283,732)、(5,205,1213)、(4,173,1276)]
10

我发现我的代码有什么问题,当我将距离重新分配给x时,我忘记了我需要用它重新分配索引,因为第一个接受测试的城市的距离最短,而在我的第一个代码中,我只在x小于距离时才重新分配变量索引

新代码:

def Nearest(Nodelist,Distance,index):
    Time_Calculation = time.time()
    Newarray=[]
    Newarray.append(Nodelist[0])
    for i in range(0,len(Nodelist)):
        for j in range(1,len(Nodelist)):
            if (Nodelist[j] not in Newarray):
                DisEquation = math.sqrt(pow(Nodelist[j][1]-Newarray[i][1],2)+pow(Nodelist[j][2]-Newarray[i][2],2))
                if Distance==0:
                    Distance=DisEquation
                    index=j
                if Distance > DisEquation:
                    index=j
                    Distance=DisEquation
        if(Nodelist[index] not in Newarray):
            Newarray.append(Nodelist[index])
        Distance=0
    print (time.time() - Time_Calculation)
    return Newarray
    ```
如果您看到我添加到代码中的注释,问题应该很清楚。循环遍历Nodelist的所有元素并调用索引i,因为您已经向NewArray添加了一个元素,所以索引0第一次存在。然后点击不在Newarray中的节点列表[index],如果为真,则Newarray会变大1,然后Newarray[1]会工作。如果出于任何原因,该值不为真,则Newarray会保持相同大小,下一个Newarray[i]将是一个索引超出范围的错误

编辑:感谢CrazyChucky在评论中为我提供了直白的信息。我已经在下面调整了

我对失败的评论是正确的,尽管我没有确定根本原因,也没有像作者所确定的那样设置索引。我没有在头脑中正确地解析代码。更新版本中的代码可以正常工作,但如果您执行以下操作,则会更快、更容易阅读:

def new_nearest(Nodelist):
    start_time = time.time()
    shortest_path = [Nodelist[0]]
    Nodelist = Nodelist[1:]
    while len(Nodelist) > 0:
        shortest_dist_sqr = -1
        next_node = None
        for potential_dest in Nodelist:
            dist_sqr = (shortest_path[-1][1] - potential_dest[1])**2 + (shortest_path[-1][2] - potential_dest[2])**2 #you don't keep the distances so there is no need to sqrt as if a > b then a**2 > b**2
            if shortest_dist_sqr < 0 or dist_sqr < shortest_dist_sqr:
                next_node = potential_dest
                shortest_dist_sqr = dist_sqr
        shortest_path.append(next_node)
        Nodelist.remove(next_node)
    print(time.time() - start_time)
    return shortest_path
def new_最近(节点列表):
开始时间=time.time()
最短路径=[Nodelist[0]]
节点列表=节点列表[1:]
而len(节点列表)>0:
最短距离sqr=-1
下一个节点=无
对于节点列表中的潜在目的地:
dist_sqr=(最短路径[-1][1]-潜在路径[1])**2+(最短路径[-1][2]-潜在路径[2])**2#您不需要保持距离,因此不需要像a>b然后a**2>b**2那样进行sqrt
如果最短距离小于0或距离小于最短距离:
下一个节点=潜在目的地
最短距离=距离
最短路径追加(下一个节点)
Nodelist.remove(下一个节点)
打印(time.time()-开始时间)
返回最短路径
这将返回相同的结果,但执行速度更快。更改为从内部循环中删除节点的方法可以更清楚地了解正在发生的事情,这可能会使代码速度慢一些(在C中可能会慢一些,但python在不同的地方有很多开销,这可能会带来净收益,)因为没有必要计算实际距离,因为你不存储它,你可以比较距离的平方,而不做任何平方根。如果确实需要距离,则可以在确定最近的节点后,将其平方根

编辑:我忍不住检查了一下。从Nodelist中删除节点实际上代表了大部分时间的节省,而缺少sqrt确实可以可靠地加快速度(我使用了timeit并改变了代码)。在较低级别的语言中,做微小的事情是非常快的,因此可能会更快地离开数组,跳过已经使用的元素(这可能不是真的,因为它会干扰分支预测性能分析非常困难,并且取决于您使用的处理器体系结构…)在python中,即使是很小的东西也非常昂贵(添加两个变量:找出它们的类型,解码变量字节长度整数,执行添加,为结果创建新对象…)因此,即使从列表中删除一个值可能比跳过值并单独保留列表更昂贵,但这将导致更多在Python中非常缓慢的小操作。如果使用低级语言,您也可以认识到节点的顺序是任意的(除了哪个是第一个,)因此,您可以使用一个包含所有节点的数组,而不是创建一个新的小ar
def new_nearest(Nodelist):
    start_time = time.time()
    shortest_path = [Nodelist[0]]
    Nodelist = Nodelist[1:]
    while len(Nodelist) > 0:
        shortest_dist_sqr = -1
        next_node = None
        for potential_dest in Nodelist:
            dist_sqr = (shortest_path[-1][1] - potential_dest[1])**2 + (shortest_path[-1][2] - potential_dest[2])**2 #you don't keep the distances so there is no need to sqrt as if a > b then a**2 > b**2
            if shortest_dist_sqr < 0 or dist_sqr < shortest_dist_sqr:
                next_node = potential_dest
                shortest_dist_sqr = dist_sqr
        shortest_path.append(next_node)
        Nodelist.remove(next_node)
    print(time.time() - start_time)
    return shortest_path
def newer_nearest(Nodelist):
    shortest_path = [Nodelist[0]]
    Nodelist = Nodelist[1:]
    while len(Nodelist) > 0:
        shortest_dist_sqr = -1
        next_node = None
        for index, potential_dest in enumerate(Nodelist):
            dist_sqr = (shortest_path[-1][1] - potential_dest[1])**2 + (shortest_path[-1][2] - potential_dest[2])**2 #you don't keep the distances so there is no need to sqrt as if a > b then a**2 > b**2
            if shortest_dist_sqr < 0 or dist_sqr < shortest_dist_sqr:
                next_node = index
                shortest_dist_sqr = dist_sqr
        shortest_path.append(Nodelist[next_node])
        Nodelist[next_node] = Nodelist[-1]
        Nodelist = Nodelist[:-1]
    return shortest_path