python中指向指针的指针

python中指向指针的指针,python,c,pointers,python-3.x,Python,C,Pointers,Python 3.x,我对python比较陌生,正在尝试理解如何将python与C/C++联系起来。考虑这个问题:检查给定的链表是否是回文。由此,我找到了一个非常有效的解决方案: // Initial parameters to this function are &head and head bool isPalindromeUtil(struct node **left, struct node *right) { /* stop recursion when right becomes NULL

我对python比较陌生,正在尝试理解如何将python与C/C++联系起来。考虑这个问题:检查给定的链表是否是回文。由此,我找到了一个非常有效的解决方案:

// Initial parameters to this function are &head and head
bool isPalindromeUtil(struct node **left, struct  node *right)
{
   /* stop recursion when right becomes NULL */
   if (right == NULL)
      return true;

   /* If sub-list is not palindrome then no need to
       check for current left and right, return false */
   bool isp = isPalindromeUtil(left, right->next);
   if (isp == false)
      return false;

   /* Check values at current left and right */
   bool isp1 = (right->data == (*left)->data);

   /* Move left to next node */
   *left = (*left)->next;

   return isp1;
}

// A wrapper over isPalindromeUtil()
bool isPalindrome(struct node *head)
{
   isPalindromeUtil(&head, head);
}
基本上,指向指针的指针被分配到前面(左指针),指针被分配到列表的末尾(右指针)。一旦指针到达各自的位置,它们就会递归并找到匹配的值。这里,*left维护指针的状态,该指针的值在递归循环中保持不变。python中的一个解决方案是将左指针与布尔值一起传递回去。但是,如果使用了多个指向指针的指针,则返回元素的数量会激增!糟糕的设计。还有别的办法吗

编辑:

非常感谢您的回复!我忘了提到我不是在试图解决回文问题。我试图理解是否有一种类似于python的处理指针的方法。我试图理解的是,如果有人向我提出一个使用数据结构(如链表)的问题,我应该尝试将其转换为其他数据结构(如列表),还是需要创造性地使用相同的数据结构来解决问题。由于指针指向指针在链表和BST中是一个非常重要的概念,是否有一个等效的解决方案或解决方案

编辑#2: 我得到的大致代码如下。但是,左侧ptr仍然卡在相同的位置,因为它是指针,而不是指向指针的指针:

def palindrome_utils(self, left_ptr, right_ptr):
        if right_ptr is None:
                return True
        prev_result = self.palindrome_utils(left_ptr, right_ptr.get_link())

        cur_result = left_ptr.get_data() == right_ptr.get_data()
        left_ptr = left_ptr.get_link()
        return cur_result and prev_result

def palindrome(self):
        return self.palindrome_utils(self.head, self.head)

Python没有像C/C++那样的指针概念,因此肯定没有双指针。但所有对象(基本类型除外)都是引用(非常量)。如果你有一个节点类,你可以用一种非常相似的方式来编写算法。

如果你的数据结构实现了正确的接口,python的方式就是不用担心序列细节和使用

import itertools
def is_palindrome(seq):
  for l, r in itertools.izip(iter(seq), reversed(seq)):
    if l!=r:
      return False
  return True

当然,如果你真的想为性能原因而努力(你可能最终会变得更慢……),你可以做与C++相同的事情。 对于任意iterable,可以使用迭代器
item(seq)
reversed(seq)
,方法与指针相同。他们甚至可以方便地为您提供
next
方法,该方法的功能完全相同

对于不提供iterable接口的自定义数据结构,可以创建自己的指针式结构。虽然python没有每个see的指针,但它有绑定到名称的引用,这些名称可以绑定到持久对象

class pointer(object):
  def __init__(self, obj):
    self.obj = obj

您可以将这样的容器类传递到函数中,对其进行修改,并隐式地将修改应用于调用框架。对于简单的情况,现有的数据结构(如
dict
list
)更为轻量级,它们也使用引用并且是可变的。

如果希望递归,可以对序列进行切片:

def is_palindrome(seq):
    if len(seq) < 2:
        return True
    return seq[0] == seq[-1] and is_palindrome(seq[1:-1])
def是回文(seq):
如果len(seq)<2:
返回真值
返回seq[0]==seq[-1]且为回文(seq[1:-1])

然而,Python中的递归是不受鼓励的

EDIT:Added
l==l[::-1]
因为
是回文5
,速度非常快,而且是迄今为止最具可读性和通俗易懂的

检查回文的最快速度是一行:

def is_palindrome1(l):
    return l[:len(l) / 2] == l[(len(l)+1) / 2:][::-1]

检查非回文是最快的,这个Python转换C++函数在你的问题:

def is_palindrome2(l):
        left = 0
        right = len(l) - 1
        for i in xrange(0,len(l) / 2):
            if l[right] != l[left]:
                return False
            left += 1
            right -= 1
        return True
这是因为该函数在开始比较元素之前不会创建任何新列表。 请注意,我使用了第一个和最后一个元素不同的非回文,因此检查会在第一次比较后立即返回(非回文的情况并不总是如此)

我还测试了Mistermiagi(
是回文3
)和PM 2Ring(
是回文4
)的答案:

结果:

is_palindrome1 small list: palindrome: 0.093779 non-palindrome: 0.073669
is_palindrome2 small list: palindrome: 0.087658 non-palindrome: 0.048855
is_palindrome3 small list: palindrome: 0.085866 non-palindrome: 0.056385
is_palindrome4 small list: palindrome: 0.139685 non-palindrome: 0.123519
is_palindrome5 small list: palindrome: 0.021798 non-palindrome: 0.022422
is_palindrome1 big list: palindrome: 1.589591 non-palindrome: 0.432679
is_palindrome2 big list: palindrome: 9.414250 non-palindrome: 0.043481
is_palindrome3 big list: palindrome: 7.315568 non-palindrome: 0.056859
is_palindrome4 big list: palindrome: 6.655833 non-palindrome: 0.128915
is_palindrome5 big list: palindrome: 2.095099 non-palindrome: 0.283472

以下是MisterMiyagi答案的一个变体,它不会对每一对进行两次测试:

导入itertools
def是回文(seq):
maxi=(1+len(seq))//2
对于itertools.izip中的i,l,r(xrange(maxi),iter(seq),reversed(seq)):
#打印左,右
如果我r:
返回错误
返回真值
数据=('abcba'、'123321'、'ABCDBA')
对于数据中的seq:
打印顺序,是回文(顺序)
a=列表(序号)
打印a,是回文(a)
输出

abcba True
['a', 'b', 'c', 'b', 'a'] True
123321 True
['1', '2', '3', '3', '2', '1'] True
ABCDBA False
['A', 'B', 'C', 'D', 'B', 'A'] False
或者,作为一个班轮:

def是回文(seq):
返回全部(l==r)
对于itertools.izip(xrange((1+len(seq))//2)中的u,l,r,
国际热核实验堆(序号),反向(序号)

请注意,
all()
短路,因此一旦检测到不匹配,它将立即退出。

Python回文检查器最优化的版本如下:

def is_palindrome(s):
    s = ''.join(s) # just in case a deque is passed
    return s==s[::-1]

当然,我正在优化编写、调试和维护代码所需的时间。如果你想优化内存或处理时间,你可以做很多事情,包括在C或汇编中写,但是你应该在尝试之前绝对确定你需要这种优化。

< P>你可以用C++代码做同样的事情。p> 您有一个包含两个成员“data”和“next”的类节点,用于生成自制链表

使用对节点的引用,而不是指向节点的指针。 使用包含一个节点元素的列表,而不是指向指针的指针

以下是可以成为代码相关部分的内容

# Recursive call
isp = isPalindromeUtil(left, right.next);

# A wrapper over isPalindromeUtil()
def isPalindrome(head)
    return isPalindromeUtil([head], head)

# Move left to next node 
   left[0] = left[0].next

这样,它将像C++代码一样工作,也就是说,当你“向左移动到下一个节点”时 在函数中,它也将为函数的调用者移动

这不是执行递归调用的推荐方法。这个例子不是一个好的设计。它的评论也很糟糕:“若子列表不是回文的,那个么就不需要检查当前的左和右,返回false”。这是错误的。如果列表为“ABCDEF”,
# Recursive call
isp = isPalindromeUtil(left, right.next);

# A wrapper over isPalindromeUtil()
def isPalindrome(head)
    return isPalindromeUtil([head], head)

# Move left to next node 
   left[0] = left[0].next