- 链表末尾插入结点(P49)
- 删除指定值的结点(P50)
- 从尾到头打印链表(P51)(面试题5)
1.链表末尾插入结点(P49)
思路如下:
- 传入的头结点要么是二级指针,要么是指针引用,因为链表为空时,插入新结点要改变头指针
- 新建一个结点,判断头指针是否为NULL,即链表是否存在
- 存在:就找到尾结点插入;不存在就直接赋值给pHead
2.删除指定值的结点(P50)
思路如下:
- 判断传入头指针是否为空
- 要考虑找不到指定值的情况,设一个pToBeRemove=NULL,遍历后仍为NULL则说明不存在
- 删除【非头结点】时要找到其父结点,即pTempNode->m_pNext->value==value时(画图清楚),执行删除
- 因为头结点没有父结点,所以删除【头结点】和【其余结点】方式不一样,要判断
3.从尾到头打印链表(P51)(面试题5)
题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值
思路如下:
- 传入参数pHead可以是*而不必是*&
- 不改变链表结构的遍历逆序打印,就是先找个地方存下来,然后FILO,这种方法是【栈】+【循环】,鲁棒性好
- 能用【栈】肯定能用【递归】,【递归】代码短,但是链表大的话可能导致函数调用栈溢出,且如果终止条件选得不好的话,容易写错
测试用例:
- 功能测试(输入链表有多个结点,输入链表只有一个结点)
- 特殊输入测试(输入链表头结点指针NULL)
- 特别提一下:定义指针的时候就初始化成NULL或另一个指针,是良好的编程习惯
三部分的代码和测试用例如下:
#include<iostream>
#include<stack>
using namespace std;
struct ListNode
{
int m_nValue;
ListNode *m_pNext;
};
void AddToTail(ListNode *&pHead,int value)
{//在末尾插入结点
ListNode *pNew = new ListNode(); //新建结点
pNew->m_nValue = value;
pNew->m_pNext = NULL;
if(pHead == NULL) //判断是否为空结点,即链表不存在
pHead = pNew;
else
{
ListNode *pTempNode = pHead;
while (pTempNode->m_pNext != NULL)
pTempNode = pTempNode->m_pNext;
pTempNode->m_pNext = pNew;
}
}
//删除指定值的结点
void RemoveNode(ListNode *&pHead,int value)
{
if(pHead == NULL)
return;
ListNode *pToBeRemove=NULL; //遍历后为NULL则说明不存在
if(pHead->m_nValue==value) //头指针删除的方式不同
{
pToBeRemove = pHead;
pHead = pHead->m_pNext;
}else{
ListNode *pTempNode = pHead;
while(pTempNode->m_pNext!=NULL)
{
if(pTempNode->m_pNext->m_nValue == value)
{
pToBeRemove = pTempNode->m_pNext;
pTempNode->m_pNext=pTempNode->m_pNext->m_pNext;
break;
}
pTempNode=pTempNode->m_pNext;
}
}
if(pToBeRemove!=NULL) //遍历后为NULL则说明不存在
{
delete pToBeRemove;
pToBeRemove = NULL;
}
}
//从尾到头打印链表,栈实现
void PrintListReserveIteratively(ListNode *pHead)
{
ListNode *pTempNode = pHead;
stack<ListNode*> iNodeStack; //用栈实现FILO
while(pTempNode != NULL) //若pHead为NULL,不会进入循环
{
iNodeStack.push(pTempNode);
pTempNode=pTempNode->m_pNext;
}
while(!iNodeStack.empty())
{
pTempNode = iNodeStack.top();
cout<<pTempNode->m_nValue<<' ';
iNodeStack.pop();
}
}
//从尾到头打印链表,递归实现
void PrintListReserveRecursively(ListNode *pHead)
{
// if(pHead != NULL) //判断最初的头指针是否为NULL
// {
// if(pHead->m_pNext != NULL)
// PrintListReserveRecursively(pHead->m_pNext);
// cout<<pHead->m_nValue<<' ';
// }
if(pHead == NULL)
return;
PrintListReserveRecursively(pHead->m_pNext);
cout<<pHead->m_nValue<<' ';
}
int main()
{
//Test1
ListNode *pHead=NULL;
PrintListReserveIteratively(pHead);
cout<<endl;
PrintListReserveRecursively(pHead);
cout<<endl;
cout<<"Test1:逆序打印 NULL 正常"<<endl;
//Test2
AddToTail(pHead,2);
cout<<"Test2:pHead==NULL尾部插入2 正常:"<<pHead->m_nValue<<endl;
//Test3
PrintListReserveIteratively(pHead);
cout<<endl;
PrintListReserveRecursively(pHead);
cout<<endl;
cout<<"Test3:逆序打印一个结点 正常"<<endl;
//Test4
AddToTail(pHead,4);
cout<<"Test4:pHead≠NULL 尾部插入4 正常:"<<pHead->m_pNext->m_nValue<<endl;
//Test5
AddToTail(pHead,6);
AddToTail(pHead,8);
AddToTail(pHead,10);
AddToTail(pHead,12);
PrintListReserveIteratively(pHead);
cout<<endl;
PrintListReserveRecursively(pHead);
cout<<endl;
cout<<"Test5:逆序打印多个结点 正常"<<endl;
//Test6、7、8、9
RemoveNode(pHead,9);
PrintListReserveIteratively(pHead);cout<<"Test6:删除不存在 正常"<<endl;
RemoveNode(pHead,2);
PrintListReserveIteratively(pHead);cout<<"Test7:删除头结点 正常"<<endl;
RemoveNode(pHead,8);
PrintListReserveIteratively(pHead);cout<<"Test8:删除中间结点 正常"<<endl;
RemoveNode(pHead,12);
PrintListReserveIteratively(pHead);cout<<"Test9:删除尾结点 正常"<<endl;
}