将节点移动到节点链

时间:2017-02-02 21:18:14

标签: python python-3.x linked-list nodes

我有一个功能,我必须移动现有代码,例如

def print_chain_and_ids(chain):
    current = chain
    while current != None:
        print(id(current), current.get_data())
        current = current.get_next()

a = Node('first')
b = Node('middle')
c = Node('last')
a.set_next(b)
b.set_next(c)

print_chain_and_ids(a)
move_node_to_end(a, 'middle')    

print_chain_and_ids(a)

所以现在这条链是:

a ----> b ----> c

链接末尾的节点c

如果我想将节点b移动到链的末尾,那么它就是:

a ----> c ----> b

这样它就不会改变最后一个节点的值,而只是移动它。我有一个节点类准备好了:

class Node:
    def __init__(self, init_data):
        self.data = init_data
        self.next = None

    def get_data(self):
        return self.data

    def get_next(self):
        return self.next

    def set_data(self, new_data):
        self.data = new_data

    def set_next(self, new_next):
        self.next = new_next

    def __str__(self):
        return str(self.data)

我想知道如何做到这一点。

我想制作一个函数,它接受两个输入,即链的第一个节点,以及移动到链的最后位置的值。所以:

def node_to_end(first_node, value_to_move):
    .....

这是我必须修改节点位置的地方。所以要移动的值会到达最后一个位置。

a = Node('blue')
b = Node('red')
c = Node('green')

a.set_next(b)
b.set_next(c)

会导致blue red green

node_to_end(a, 'red') 

会创建一个

blue green red

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

您的节点链与所谓的单链表非常相似。有了这些节点,通常通过在遍历列表时跟踪上一个节点来删除节点,这样当找到目标节点时,您就会知道哪一个节点(如果有的话)在它之前。拥有这条信息可以轻松修改列表。

以下是如何将其应用于您的代码。我还添加了一个小工具来打印链的内容,以便清楚它们中的内容。

class Node:
    def __init__(self, init_data):
        self.data = init_data
        self.next = None

    def get_data(self):
        return self.data

    def get_next(self):
        return self.next

    def set_data(self, new_data):
        self.data = new_data

    def set_next(self, new_next):
        self.next = new_next

    def __str__(self):
        return str(self.data)

def move_to_end(start, target):
    """Move target node from the chain beginning with start to end."""
    previous = None
    current = start
    while current:
        if current.get_next() is target:
            previous = current
            break
        current = current.get_next()

    if previous:  # target found in chain?
        previous.set_next(target.get_next())  # remove it
        # and move it to the end
        current = target
        while current:
            if not current.get_next():  # last node in chain?
                target.set_next(None)
                current.set_next(target)
                break
            current = current.get_next()

def print_node_chain(start):
    """Utility to print out a node chain starting from given node."""
    values = []
    current = start
    while current:
        values.append(str(current))
        current = current.get_next()

    print(' ----> '.join(values) + ' ----> None')

a = Node('blue')
b = Node('red')
c = Node('green')

a.set_next(b)
b.set_next(c)

print_node_chain(a)
move_to_end(a, b)
print_node_chain(a)

输出:

blue ----> red ----> green ----> None
blue ----> green ----> red ----> None

答案 1 :(得分:1)

这需要一些计算。让我们假设一般情况:

e i-1 - &gt; e i - &gt; e i + 1 - &gt; ... - &gt; Ë<子>名词

现在我们想将 e i 移到最后一个位置:

e i-1 - &gt; e i + 1 - &gt; ... - &gt; e n - &gt; Ë<子> I

所以问题是:应该改变什么?根据一般情况,有三个指针必须改变:

  • e i-1 现在指向 e i + 1 ;
  • e i 现在什么也没有(None);和
  • e n 现在指向 e i

现在由于链表是没有双重链接:一个节点没有引用前一个节点,我们唯一可以做的就是获取前一个元素,从根节点迭代直到我们找到元素:

def get_prev_element(root,node):
    while root.get_next() is not node:
        root = root.get_next()

一旦我们拥有了前一个元素,我们就可以将它链接到下一个元素:

previous.set_next(node.get_next())

但是现在我们仍然需要找出最后一个元素是什么。猜猜看,我们再次通过迭代再做一遍,然而我们可以从我们自己的节点开始:

def get_last(node):
    while node.get_next() is not None:
        node = node.get_next()
    return node

现在我们将最后一个节点的next设置为我们自己的节点:

last.set_next(node)

最后我们将自己设置在None旁边:

node.set_next(None)

现在将所有这些组合在一起我们可以在节点上定义方法

class Node:

    # ...

    def get_previous(self,root):
        previous = root
        while previous.get_next() is not self:
            previous = previous.get_next()
        return previous

    def get_last(self):
        last = self
        while last.get_next() is not None:
            last = last.get_next()
        return last

    def move_last(self,root):
        previous = self.get_previous(root)
        previous.set_next(self.get_next())
        last = self.get_last()
        last.set_next(self)
        self.set_next(None)

请注意,由于链接列表不是双重链接,因此您必须为其提供根元素。

Intermezzo :鉴于您引用了abc。当然没有理由计算前一个和后一个:你知道a是前一个,c是最后一个。所以在这种情况下,代码就是:

a.set_next(c)
c.set_next(b)
b.set_next(None)

如果根元素是节点本身,则此代码不起作用。我将它作为练习来修改代码以使其正常工作。这不是很难。