【引言】
这几天在看<剑指offer>写的很好,跟July的各有千秋,更加注重归纳总结,笔试面试临时抱佛脚,决定要啃下这其中的46道题目。OK,把每道题目自己实现,相同的归成一类。这次把所有的与list相关的题目列出来。
【题目5】从尾到头打印list
//思路:从尾到头打印list的话,考虑用stack先把各节点保存起来,遍历完以后再将stack弹出打印即可
#include <stack>
void print_list_reverse(list_node* head)
{
stack<char> m_list;
if (head == NULL)
return;
list_node* node = head->m_pNext;
while(node != NULL)
{
m_list.push(node->m_data);
node = node->m_pNext;
}
while(!m_list.empty())
{
cout<<m_list.top()<<" ";
m_list.pop();
}
}
//思路:用递归模拟stack,每次遍历list当前节点的时候,递归调用下一个节点,直到list结尾
void print_list_reverse_res(list_node* head)
{
if (head == NULL)
return;
list_node* node = head;
if (node->m_pNext != NULL)
{
node = node->m_pNext;
print_list_reverse_res(node);
cout<<node->m_data<<" ";
}
}
【题目13】在O(1)时间内删除链表节点
//void delete_node_O1(list_node* head, list_node* pto_delete)函数形式;可以看出,已经给出了要删除node的指针,我们可以很方便地找到要删除node的下一个node
//将下一个node的信息复制到当前node,再将下一个node删除,这正好相当于将当前node删除!时间复杂度是O(1),需要注意的是假设当前node是最后一个的话
//node->next为空,上面的思路就不行了,我们还是需要找到尾节点的上一个节点!如果所有链表只有一个节点,那么我们将head置空即可。so,代码如下:
void delete_node_O1(list_node* head, list_node* pto_delete)
{
if (pto_delete == NULL || head == NULL)
return;
list_node* nextNode;
if (pto_delete->m_pNext != NULL)
{
nextNode = pto_delete->m_pNext;
pto_delete->m_data = nextNode->m_data;
pto_delete->m_pNext = nextNode->m_pNext;
delete nextNode;
nextNode = NULL;
}
else if (pto_delete == head)
{
delete pto_delete;
pto_delete = NULL;
head = NULL;
}
else //list尾,没办法,要将前一个节点的m_pNext置为NULL只能遍历一次
{
list_node* node = head;
while(node->m_pNext != pto_delete)
node = node->m_pNext;
nextNode = node->m_pNext;
node->m_pNext = NULL;
delete nextNode;
nextNode = NULL;
}
}
【题目15】寻找list中倒数第k个节点
//题目给出一个list,输出该链表中倒数第k个节点。
//为符合习惯本题目,从1开始计数,即list的最后一个节点是倒数第一个
//思路:使用两个指针,刚开始同时指向list头,然后第二个指针p2前进k-1步,然后第一个指针p1和p2
//同时前进,知道p2到达list尾,这时p1指向倒数第k个节点
//为符合习惯本题目,从1开始计数,即list的最后一个节点是倒数第一个
//思路:使用两个指针,刚开始同时指向list头,然后第二个指针p2前进k-1步,然后第一个指针p1和p2
//同时前进,知道p2到达list尾,这时p1指向倒数第k个节点
list_node* find_k_reverse(list_node* head, int k)
{
if (head == NULL || k < 1)
return NULL;
list_node *p1, *p2;
p1 = p2 = head;
int i = 0;
while(p2->m_pNext != NULL && (++i != k))
p2 = p2->m_pNext;
if (p2->m_pNext == NULL)//list长度小于k-1
return NULL;
while(p2->m_pNext != NULL)
{
p1 = p1->m_pNext;
p2 = p2->m_pNext;
}
return p1;
}
【题目16】反转list
//给定一个list,输入参数是头结点,要求反转list,输出翻转后list的头结点
//这类问题,都不难,最好画画图啥的,需要注意的中间需要一些节点保存指针,要不会造成list的断裂,需要三个指针,当前指针,当前指针前一个指针,当前指针后一个指针
list_node* reverse_list(list_node* head)
{
if (head == NULL)
return NULL;
//一共需要三个指针,当前节点之前,当前节点,当前节点之后的节点,这样才不会造成
//调整过程中的list的断裂
list_node* p_node = head;
list_node* p_pre = NULL;
list_node* p_next = p_node->m_pNext;
while (p_next != NULL)
{
p_node->m_pNext = p_pre;
p_pre = p_node;
p_node = p_next;
p_next = p_next->m_pNext;
}
if (p_next == NULL)//这个时候p_node就是原来的尾节点
{
p_node->m_pNext = p_pre;
}
return p_node;
}
【题目17】合并两个有序list
list_node* merge_order_list(list_node* first, list_node* second)
{
//有链表为空的情况
if(first == NULL)
return second;
if(second == NULL)
return first;
list_node* p_result = NULL;
if (first->m_data < second->m_data)
{
p_result = first;
p_result->m_pNext = merge_order_list(first->m_pNext, second);
}
else
{
p_result = second;
p_result->m_pNext = merge_order_list(first, second->m_pNext);
}
return p_result;
}