链表操作在面试过程中也是很重要的一部分,因为它和二叉树一样都涉及到大量指针的操作,而且链表本身很灵活,很考查编程功底,所以是很值得考的地方。下面是本文所要用到链表节点的定义:
template <typename Type>
struct ListNode{
Type data;
ListNode *next;
};
链表的创建可以采用下面的代码,采用尾插法进行链表的创建,返回的链表没有头节点:
/**
* Create a list, without head node
*/
template <typename Type>
ListNode<Type> *CreatList(Type *data, int len)
{
if(data == NULL || len <= 0)
return NULL;
ListNode<Type> *head, *last;
head = new ListNode<Type>;
last = head;
for (int i = 0; i < len; ++i)
{
last->next = new ListNode<Type>;
last->next->data = data[i];
last = last->next;
}
last->next = NULL;
last = head;
head = head->next;
delete last;
return head;
}
1.单链表的逆序打印
单链表的逆序打印就是重表尾开始依次往前打印,直到表头截止,所以可以将链表逆置,然后顺序打印,但这是一种劳民伤财的做法,不仅容易出错,而且还破坏了链表的结构。这里可以采用额外的空间,来保存顺序遍历的节点,在遍历完后,就可以将该辅助空间的值逆序输出,下面是采用stack实现的代码:
/**
* reversely print the list
* method 1: use the stack
*/
template <typename Type>
void ReversePrintList_1(const ListNode<Type> *head)
{
if(head == NULL)
return;
stack<Type> nodeStack;
while (head)
{
nodeStack.push(head->data);
head = head->next;
}
while(!nodeStack.empty())
{
cout<<nodeStack.top()<<" ";
nodeStack.pop();
}
cout<<endl;
}
我们知道代码中,递归和栈很多时候可以相互转化,而且通过递归实现的代码会更加简洁。下面是通过递归的方式,来实现上面的功能,代码如下:
/**
* reversely print the list
* method 2: recursively
*/
template <typename Type>
void ReversePrintList_2(const ListNode<Type> *head)
{
if(head == NULL)
return;
ReversePrintList_2(head->next);
cout<<head->data<<" ";
}
2.单链表的逆置
在前面单链表的逆序打印中,有一种方法就是把单链表逆置后,再顺序打印。单链表的逆置最高效的方法,