剑指Offer-C++操作链表
如何打印链表中倒数第k个结点
基本思想:两个指针同时指向头指针,一个先走K步,另一个走。当前一个移动到链表尾部时候,后一个则为想找到的节点。
#include <iostream>
using namespace std;
//定义结构体
struct ListNode{
int val;
ListNode* next;
};
class Solution {
public:
/*链表创建*/
void createList(ListNode* head)
{
ListNode* phead=head;
int i;
for(i=2;i<=10;i++)
{
ListNode* node=new ListNode;
node->val = i;
phead->next = node;
phead=phead->next;
}
cout<<"链表创建完成。\n";
}
/*打印链表*/
void printList(ListNode* head)
{
ListNode* phead=head;
cout<<"链表打印结果:\n";
while(phead != NULL)
{
cout<<phead->val<<" ";
phead=phead->next;
}
cout<<"\n";
}
/*找到表中倒数第k个结点*/
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
ListNode* pphead=NULL;
ListNode* phead=NULL;
phead=pListHead;
pphead=pListHead;
int a=k; //记录k的值
int count=0; //记录节点的值
//phead先走k个节点,pphead再走,当phead到达尾节点时返回pphead
while(phead!= NULL)
{
phead=phead->next;
count++;
//加入if else是为了不然k变的很大,因为k是unsigned int
if(k<1)//当k=0时,phead走k-1个点,phead此时和phead一同前移
{
pphead=pphead->next;
}else{
k--;
}
}
//节点个数小于K个
if(count<a)
return NULL;
else
return pphead;
}
};
int main()
{
Solution ss;
ListNode* head=new ListNode;
head->val=1;
head->next==NULL;
//创建链表
ss.createList(head);
//打印链表
ss.printList(head);
//找到链表中倒数第k个结点
cout<<"倒数第5个节点为:"<<ss.FindKthToTail(head,5)->val;
return 0;
}
反转链表
利用栈先进后出的思想,先用栈记录链表的逆序,再重新建链表即可。
#include <iostream>
#include <stack>
using namespace std;
//定义结构体
struct ListNode{
int val;
ListNode* next;
};
class Solution {
public:
/*链表创建*/
void createList(ListNode* head)
{
ListNode* phead=head;
int i;
for(i=2;i<=10;i++)
{
ListNode* node=new ListNode;
node->val = i;
phead->next = node;
phead=phead->next;
}
cout<<"链表创建完成。\n";
}
/*打印链表*/
void printList(ListNode* head)
{
ListNode* phead=head;
cout<<"链表打印结果:\n";
while(phead != NULL)
{
cout<<phead->val<<" ";
phead=phead->next;
}
cout<<"\n";
}
/*反转链表*/
ListNode* ReverseList(ListNode* pHead)
{
ListNode* head=pHead;//记录头指针
ListNode* reHead=NULL;
stack<int> arr;
if(pHead==NULL)
return NULL;
while(head!=NULL)
{
arr.push(head->val);//入栈
head=head->next;
}
ListNode* reverseHead=new ListNode;
reverseHead->val=arr.top();
arr.pop();
reHead=reverseHead;
while(!arr.empty())
{
ListNode* node=new ListNode;
node->val=arr.top();
arr.pop();//出栈
reverseHead->next=node;
reverseHead=node;
}
return reHead;
}
};
int main()
{
Solution ss;
ListNode* head=new ListNode;
head->val=1;
head->next==NULL;
//创建链表
ss.createList(head);
//打印链表
ss.printList(head);
//打印反转列表
cout<<"链表反转之后";
ss.printList(ss.ReverseList(head));
return 0;
}
改进后的链表反转
上面通过栈的算法能跑通,但在牛客网中会报错,个人感觉应该是因为链表的长度如果很长的情况词方法不科学。采用新方法,即通过一边断开旧链表,一边建立新的子链表。
#include <iostream>
#include <stack>
using namespace std;
//定义结构体
struct ListNode{
int val;
ListNode* next;
};
class Solution {
public:
/*链表创建*/
void createList(ListNode* head)
{
ListNode* phead=head;
int i;
for(i=2;i<=10;i++)
{
ListNode* node=new ListNode;
node->val = i;
phead->next = node;
phead=phead->next;
}
cout<<"链表创建完成。\n";
}
/*打印链表*/
void printList(ListNode* head)
{
ListNode* phead=head;
cout<<"链表打印结果:\n";
while(phead != NULL)
{
cout<<phead->val<<" ";
phead=phead->next;
}
cout<<"\n";
}
/*反转链表*/
ListNode* ReverseList(ListNode* pHead)
{
ListNode* pnode=pHead;//记录头指针
ListNode* head=NULL;//反转链表指针
ListNode* preHead=NULL;//记录新子链的头指针
if(pnode==NULL)
return NULL;
while(pnode!=NULL)
{
ListNode* pnext=pnode->next;//记录pnode后面的链表
if(pnext==NULL)//pnode移动到了最后
head=pnode;
pnode->next=preHead;
preHead=pnode;
pnode=pnext;
}
return head;
}
};
int main()
{
Solution ss;
ListNode* head=new ListNode;
head->val=1;
head->next==NULL;
//创建链表
ss.createList(head);
//打印链表
ss.printList(head);
//打印反转列表
cout<<"链表反转之后";
head=ss.ReverseList(head);
ss.printList(head);
return 0;
}