- 从尾到头打印链表(要求不改变链表结构)
- 反转链表(要求仅遍历一次链表)
- 合并两个有序链表(非递归方法)
- 删除倒数第k个节点
- 链表中环的入口节点(包括判断环的存在,确定环中节点个数等问题)
- 求链表中间节点
ListNode.h
#pragma once
#include <iostream>
using namespace std;
struct ListNode{
int val;
ListNode* next;
// 构造函数
ListNode(int val):val(val), next(nullptr){}
};
// 写链表的习惯:一般会用ListNode* pNode = pHead;
// 创建一个链表节点
ListNode* createListNode(int val){
ListNode* pNode = new ListNode(val);
pNode->val = val;
pNode->next = nullptr;
return pNode;
}
// 链接两个节点
void connectListNodes(ListNode* pCurrent, ListNode* pNext){
if(pCurrent == nullptr)
cout<<"Error to connect two nodes."<<endl;
else
pCurrent->next = pNext;
}
// 打印某个节点的值
void PrintListNode(ListNode* pNode){
if(pNode == nullptr)
cout<<"error to print a node."<<endl;
else
cout<<pNode->val<<endl;
}
// 打印pHead之后的链表(只要有下一个节点就接着打印)
void PrintListNodes(ListNode* pHead){
if(pHead == nullptr)
cout<<"error to print nodes."<<endl;
else{
ListNode* pNode = pHead;
while(pNode != nullptr){
cout<<pNode->val<<endl;
pNode = pNode->next;
}
}
}
// 销毁从pHead开始之后的链表
void destroyListNodes(ListNode* pHead){
if(pHead == nullptr)
cout<<"error to destroy nodes."<<endl;
else{
ListNode* pNode = pHead;
while(pNode != nullptr){
pHead = pNode->next;
delete pNode;
pNode = nullptr;
}
}
}
// 往链表的尾部添加一个节点(注意可能此时链表为空,添加节点会修改头指针,所以使用二级指针ListNode** pHead)
void addToTail(ListNode** pHead, int val){
ListNode* pNew = new ListNode(val);
pNew->val = val;
pNew->next = nullptr;
// 如果头指针为空,则添加的节点为头指针
if(*pHead == nullptr){
*pHead = pNew;
}
else{
ListNode* pNode = *pHead;
// 这里应该写成pNode->next != null,如果写成pNode != null,那么pNode循环结束就是空了,下面的pNode->next = pNew就是错的
while(pNode->next != nullptr){
pNode = pNode->next;
}
pNode->next = pNew;
}
}
// 找到第一个含有某值的节点并删除该节点,也有可能修改头指针,所以也要写成二级指针ListNode** pHead
void removeNode(ListNode** pHead, int val){
if(*pHead == nullptr)
return ;
// 如果头指针的值就是val,那么要删除头指针,并将头指针指向下一个节点
ListNode* pToBeDelete = nullptr;
if((*pHead)->val == val){
pToBeDelete = *pHead;
*pHead = (*pHead)->next;
}
// 如果是中间节点(注意,也有可能是最后一个节点)
else{
ListNode* pNode = *pHead;
while(pNode->next != nullptr && pNode->next->val != val)
pNode = pNode->next;
if(pNode->next != nullptr && pNode->next->val == val){
pToBeDelete = pNode->next;
// 注意,最后一个节点也可以删除,并使最后一个节点的前一个节点指向空(pNode->next->next就是空)
pNode->next = pNode->next->next;
}
}
// 如果是尾节点
if(pToBeDelete != nullptr){
delete pToBeDelete;
pToBeDelete = nullptr;
}
}
// 迭代法反转链表
ListNode* reverseList(ListNode* pHead){
if(pHead == nullptr)
return pHead;
ListNode* pNode = pHead;
ListNode* reverseNode = nullptr;
ListNode* pPrev = nullptr;
while(pNode != nullptr){
ListNode* pNext = pNode->next;
if(pNext == nullptr)
reverseNode = pNode;
pNode->next = pPrev;
pPrev = pNode;
pNode = pNext;
}
return reverseNode;
}
// 递归法反转单链表
ListNode* reverseListPlus(ListNode* pHead){
if(pHead == nullptr || pHead->next == nullptr)
return pHead;
ListNode* reverseNode = reverseListPlus(pHead->next);
pHead->next->next = pHead;
pHead->next = nullptr;
return reverseNode;
}
main.cpp
#include <iostream>
#include <vector>
#include <stack>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include "TreeNode.h"
#include "ListNode.h"
using namespace std;
// 面试题6
// 从尾到头打印链表
void printListReverse(ListNode* pHead){
stack<int> stack1;
//
ListNode* pNode = pHead;
while(pNode != nullptr){
stack1.push(pNode->val);
pNode = pNode->next;
}
cout<<endl;
while(!stack1.empty()){
cout<<stack1.top();
stack1.pop();
}
}
// 面试题24
// 反转链表
ListNode* reverseList(ListNode* pHead){
if(pHead == nullptr)
return pHead;
ListNode* pNode = pHead;
ListNode* pPrev = nullptr;
ListNode* pReverseHead = nullptr;
while(pNode != nullptr){
ListNode* pNext = pNode->next;
if(pNext == nullptr)
pReverseHead = pNode;
pNode->next = pPrev;
pPrev = pNode;
pNode = pNext;
}
return pReverseHead;
}
// 合并两个有序链表(非递归方法)
ListNode* mergeList(ListNode* pHead1, ListNode* pHead2){
if(pHead1 == nullptr)
return pHead2;
if(pHead2 == nullptr)
return pHead1;
ListNode* pMergeHead = nullptr;
// 先确定头指针
if(pHead1->val < pHead2->val){
pMergeHead = pHead1;
pHead1 = pHead1->next;
}
else{
pMergeHead = pHead2;
pHead2 = pHead2->next;
}
ListNode* pNode = pMergeHead;
while(pHead1 != nullptr || pHead2 != nullptr){
if(pHead1 != nullptr && pHead2 != nullptr){
if(pHead1->val < pHead2->val){
pNode->next = pHead1;
pHead1 = pHead1->next;
}
else{
pNode->next = pHead2;
pHead2 = pHead2->next;
}
}
else if(pHead1 != nullptr){
pNode->next = pHead1;
pHead1 = pHead1->next;
}
else{
pNode->next = pHead2;
pHead2 = pHead2->next;
}
pNode = pNode->next;
}
return pMergeHead;
}
// 面试题22:删除倒数第k个节点(有可能删除头节点,所以也是二级指针)
ListNode* findKthNode(ListNode** pHead, int k){
if(*pHead == nullptr || pHead == nullptr || k == 0)
return nullptr;
ListNode* pNodeFirst = *pHead;
ListNode* pNodeSecond = *pHead;
ListNode* pPrev = *pHead;
// 第一个指针先走k-1步
for(int i = 1; i <= k-1; i++){
if(pNodeFirst->next != nullptr)
pNodeFirst = pNodeFirst->next;
// 链表的节点数小于k-1个
else
return nullptr;
}
while(pNodeFirst->next != nullptr){
pNodeFirst = pNodeFirst->next;
pPrev = pNodeSecond;
pNodeSecond = pNodeSecond->next;
}
// 删除节点
// 如果删除的是头指针(或者只有一个节点)
if(pNodeSecond == *pHead){
ListNode* deleteNode = *pHead;
*pHead = (*pHead)->next;
delete deleteNode;
deleteNode = nullptr;
}
else{
pPrev->next = pPrev->next->next;
delete pNodeSecond;
pNodeSecond = nullptr;
}
return *pHead;
}
// 面试题23:链表中环的入口节点(这个题目有3个考点:1、链表中环的检测(返回相遇节点);2、环中节点个数;3、根据前两个解,找到入口节点)
// 链表中环的检测(定义两个指针,一个指针一次走两步,一个指针一次走一步,
// 如果有环,那么总有个时候两个指针会相遇,如果走的快的走到末尾仍然没有与慢指针相遇,那么没有
// 判断环中两个指针的相遇节点
ListNode* meetingNode(ListNode* pHead){
if(pHead == nullptr)
return nullptr;
ListNode* pSlow = pHead->next;
// 只有一个节点
if(pSlow == nullptr)
return nullptr;
ListNode* pFast = pSlow->next;
while(pFast != nullptr && pSlow != nullptr){
if(pFast == pSlow){
cout<<pFast->val<<endl;
return pFast;
}
pSlow = pSlow->next;
pFast = pFast->next;
if(pFast != nullptr)
pFast = pFast->next;
}
return nullptr;
}
// 寻找环中入口节点
ListNode* entryNode(ListNode* pHead){
if(pHead == nullptr)
return nullptr;
ListNode* meetingnode = meetingNode(pHead);
if(meetingnode == nullptr)
return nullptr;
// 先找到环中节点的个数
int loopNode = 1;
ListNode* meet = meetingnode;
while(meet->next != meetingnode){
meet = meet->next;
loopNode++;
}
// 定义两个指针
ListNode* pFirst = pHead;
ListNode* pSecond = pHead;
while(loopNode--)
pFirst = pFirst->next;
while(pFirst != pSecond){
pFirst = pFirst->next;
pSecond = pSecond->next;
}
cout<<pFirst->val<<endl;
return pFirst;
}
// 面试题xx:求链表中间节点
ListNode* middleNode(ListNode* pHead){
if(pHead == nullptr)
return nullptr;
ListNode* pSlow = pHead;
// 只有一个节点
if(pSlow->next == nullptr)
return pSlow;
// 只有两个节点
if(pSlow->next->next == nullptr)
return pSlow;
pSlow = pSlow->next;
ListNode* pFast = pSlow->next;
// 当快节点走过最后一个节点
while(pFast->next != nullptr){
pFast = pFast->next;
// 偶数个节点时,慢指针在最后不走
if(pFast->next != nullptr){
pFast = pFast->next;
pSlow = pSlow->next;
}
}
cout<<pSlow->val<<endl;
return pSlow;
}
int main(int argc, char* argv[]){
ListNode* pNode1 = createListNode(1);
ListNode* pNode2 = createListNode(2);
ListNode* pNode3 = createListNode(3);
ListNode* pNode4 = createListNode(4);
ListNode* pNode5 = createListNode(5);
connectListNodes(pNode1, pNode2);
connectListNodes(pNode2, pNode3);
connectListNodes(pNode3, pNode4);
connectListNodes(pNode4, pNode5);
//connectListNodes(pNode5, pNode1);
middleNode(pNode1);
//PrintListNodes(entryNode(pNode1));
return 0;
}