当前位置: 首页 > 知识库问答 >
问题:

单链表首尾交换

蓬运诚
2023-03-14

我已经在这上面困了半天了。我可以得到一些提示或指针,如何交换一个链表的头部和尾部(而不是反转整个列表),而不复制他们的数据吗?

class myNode:

    def __init__(data, next):
         self.data = data
         self.next = next


class MyLinkedList:

    def __init__(self):
         self.head = None
         self.tail = None

如果我能看到代码并对它有一个解释,那就太棒了!

编辑:

    null

通过列表查找列表的第二个最后节点,并将其链接到头部。

将原来的头部链接到null,就像现在一样,头部应该被交换到尾部。

共有1个答案

商飞翮
2023-03-14

有一些边缘情况最好单独处理,以保持代码简单。它们是大小为零、一和二的列表。

对于其中的前两个,列表根本不会改变。对于大小2,只有头部和尾部会改变,内部节点不会改变(因为没有内部节点)。

在这种情况下,左边的列表变成右边的列表(表示空指针,h/t表示头部和尾部指针):

h    t               h    t
A -> B -> |          B -> A -> |

使用(这是伪代码而不是Python,.n指定next指针):

                     h=A  t=B  A.n=B  B.n=|
tail.next = head     h=A  t=B  A.n=B  B.n=A
head.next = null     h=A  t=B  A.n=|  B.n=A
swap head, tail      h=B  t=A  A.n=|  B.n=A

对于所有其他情况(三个或更多节点),倒数第二个节点的指针必须更改为指向新的尾部。上面的两个节点的情况可能更容易,因为它知道头部是倒数第二个。下图显示了大小为4的情况(我已经用P标记了倒数第二个节点):

h         p    t          h         p    t
A -> B -> C -> D -> |     D -> B -> C -> A -> |

这可以通过以下操作实现:

                          h=A  t=D  p=C A.n=B  B.n=C C.n=D  D.n=|
tail.next = head.next     h=A  t=D  p=C A.n=B  B.n=C C.n=D  D.n=B
head.next = None          h=A  t=D  p=C A.n=|  B.n=C C.n=D  D.n=B
penu.next = head          h=A  t=D  p=C A.n=|  B.n=C C.n=A  D.n=B
swap head, tail           h=D  t=A  p=C A.n=|  B.n=C C.n=A  D.n=B
class MyNode:
    def __init__(self, data, next = None):
         self.data = data
         self.next = next

class MyList:
    def __init__(self):
         self.head = None
         self.tail = None

    def push_back(self, data):
        if self.tail is None:
            self.head = MyNode(data)
            self.tail = self.head
        else:
            self.tail.next = MyNode(data)
            self.tail = self.tail.next

    def dump(self, desc):
        print(desc, end=' ')
        node = self.head
        while node is not None:
            print(node.data, end=' -> ')
            node = node.next
        print('|')

    def swap(self):
        # For empty and size 1, no change.

        if self.head is None: return
        if self.head.next is None: return

        # For size 2, easy swap.

        if self.head.next.next is None:
            self.tail.next = self.head
            self.head.next = None
            self.head, self.tail = self.tail, self.head
            return

        # For size 3+, little more complex, need the
        # penultimate node as well as head and tail.

        penu = self.head
        while penu.next != self.tail:
            penu = penu.next

        self.tail.next = self.head.next
        self.head.next = None
        penu.next = self.head
        self.head, self.tail = self.tail, self.head

当然,如果没有某种测试代码,什么自尊类会存在。下面将测试不同大小的列表,以便您可以看到swap操作按预期工作:

x = MyList()

# Do various sizes.

for i in range(6):
    # Add an element except for first time (so we check empty list).

    if i > 0:
        x.push_back(i)

    # Show before and after figures, making sure we restore
    # list to original state.

    x.dump('Size = %d, before:'%(i))
    x.swap()
    x.dump('Size = %d, after :'%(i))
    x.swap()
    print()

运行此代码将导致:

Size = 0, before: |
Size = 0, after : |

Size = 1, before: 1 -> |
Size = 1, after : 1 -> |

Size = 2, before: 1 -> 2 -> |
Size = 2, after : 2 -> 1 -> |

Size = 3, before: 1 -> 2 -> 3 -> |
Size = 3, after : 3 -> 2 -> 1 -> |

Size = 4, before: 1 -> 2 -> 3 -> 4 -> |
Size = 4, after : 4 -> 2 -> 3 -> 1 -> |

Size = 5, before: 1 -> 2 -> 3 -> 4 -> 5 -> |
Size = 5, after : 5 -> 2 -> 3 -> 4 -> 1 -> |

一旦您对此工作感到满意,您可能需要考虑将penu(倒数第二个节点指针)变成一个成员,就像headtail一样,如果大小是两个或更小,则将其设置为none。这样,您就不必在每次交换节点时都进行搜索。每当调用push_back(或任何其他更改列表大小的方法)时,更新它应该比较容易。

 类似资料:
  • 如果你想创建一个像这样的单链表: 这个列表有方法“追加”、“删除”、“printList”和“findElement”。有必要有尾巴吗?因为使用“最后”你可以地址最后一个节点。 那么,什么时候有必要拥有所有三个节点“头”、“尾”和“最后”?例如,当您想将排序的节点插入列表时?

  • 我正在尝试为我的链表类创建一个添加和删除方法。我写了两封信,名字是Head和Tail。 头- 当我试图删除特定节点时,我一直遇到问题,因为Java说我越界了。我想是因为我的头没有指向第一个节点?你们觉得怎么样?还是我完全走错路了...

  • [采访问题] 编写一个函数,该函数将在一次传递中从单个链表整数的尾部(或尾部)返回第5个元素,然后提供一组针对该函数的测试用例。 这类似于问题:如何从单链表的末尾找到第n个元素?,但是我还有一个额外的要求,我们应该只遍历链接列表一次。 这是我的解决方案: 我只遍历链表一次,并使用隐式递归堆栈。另一种方法是有两个指针:快指针和慢指针,快指针是比慢指针快的k个指针。哪一个看起来更好?我认为有两个指针的

  • 似乎人们总是说,如果一个单链接列表的头是空的,那么这个列表是空的,但是检查尾部也会起作用吗?假设我确实知道一个列表有一个尾部,我可以检查尾部是否为空以确定它是否为空吗?

  • 我正在尝试交换双链接列表中的两个节点。下面是具有交换功能的程序部分。 当我运行这个程序时,在第一个和第二个节点的情况下,它崩溃了。而在任何其他节点的情况下,它提供无限循环输出。(例如:-2- 我知道还有一些关于节点交换的问题,但是我没有找到任何与我的问题相似的问题。请帮帮我...!! 提前谢谢。