鲁棒是英文Robust的音译,有时也翻译成健壮性。所谓的鲁棒性是指程序能够判断输入是否合乎规范要求,并对不合要求的输入予以合理的处理。
容错性
15 链表中倒数第k个结点
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
//由于返回的是倒数第k个结点,所以返回类型是ListNode
ListNode* getKthFromEnd(ListNode* head, int k) {
//如果头指针为空或者返回倒数第0个节点,则返回空指针
if (head == nullptr || k == 0) {
return nullptr;
}
ListNode *pHead = head;
ListNode *pBehind = nullptr;
/*
*前面的指针先走k-1步时,后面的指针
*在第0步(pBehind = head),随后以两
*者相距k-1步的距离同速向前走。
*/
for (int i = 0; i < k - 1; ++i) {
if (pHead -> next != nullptr) {
pHead = pHead -> next;
} else { //链表总长度少于k个
return nullptr;
}
}
pBehind = head;
while (pHead -> next != nullptr) {
pHead = pHead -> next;
pBehind = pBehind -> next;
}
return pBehind;
}
};
16 反转链表
方法一:利用三个指针进行反转链表
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead)
{
//输入的链表头指针为NULL或者整个链表只有一个结点时
if(pHead == nullptr || pHead->next == nullptr)
return pHead;
ListNode *pReversedHead = nullptr;//后一个结点
ListNode *pPre = nullptr;//前一个结点
ListNode *pNode = pHead;//当前结点
ListNode *pNext = nullptr;
while (pNode != nullptr) {
pNext = pNode->next; //pNext保存pNode的下一个结点
if (pNext == nullptr) //pNode的下一个结点为空时,为尾结点
pReversedHead = pNode;//记录反转后的头结点
pNode->next = pPre; //指针反向,
pPre = pNode; //移动pPre
pNode = pNext; //移动pNode
}
return pReversedHead;//返回头结点(即原来的尾结点)
}
};
方法二:利用递归
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
//如果链表为空或者链表中只有一个元素
if(pHead==NULL||pHead->next==NULL) return pHead;
//先反转后面的链表,走到链表的末端结点
ListNode* pReverseNode=ReverseList(pHead->next);
//再将当前节点设置为后面节点的后续节点
pHead->next->next=pHead;
pHead->next=NULL;
return pReverseNode;
}
};
键盘输入创建链表
#include<iostream>
using namespace std;
struct ListNode
{
int val;
ListNode* next;
ListNode() :val(0), next(nullptr) {};
ListNode(int x) : val(x), next(nullptr) {};
};
ListNode* create(int n)
{
auto dummy = new ListNode(0);
auto pre = dummy;
for (int i = 0; i < n; i++)
{
auto p = new ListNode(0);
cin >> p->val;
pre->next = p;
pre = pre->next;
}
return dummy->next;
}
void print(ListNode* head)
{
while (head)
{
if (head->next == NULL)
cout << head->val<<"-> NULL";
else
cout << head->val << "-> ";
head = head->next;
}
cout << endl;
}
int main()
{
int n;
cout << "链表的长度为:" << endl;
cin >> n;
cout << endl;
cout << "依次输入元素的值(enter键换行)" << endl;
auto head = create(n);
cout << "链表输出为:" << endl;
print(head);
system("pause");
return 0;
}
合并两个排序的链表
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
//递归!!!!
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{ //鲁棒性,①链表1为空时,返回链表2;②链表2为空时,返回链表1;③链表1、2均为空时,返回空表;
if(pHead1 == nullptr)
return pHead2;
else if(pHead2 == nullptr)
return pHead1;
ListNode* pMergeHead = nullptr;//新链表的指针
if(pHead1->val < pHead2->val){ //每次选出剩下两个链表合并后的头指针
pMergeHead = pHead1;
pMergeHead->next = Merge(pHead1->next,pHead2);
}
else{ //包括小于等于
pMergeHead = pHead2;
pMergeHead->next = Merge(pHead1,pHead2->next);
}
// return pMergeHead;
}
};
树的子结构
我们注意到上述代码有多处判断一个指针是不是NULL,这样做是为了避免试图访问空指针而造成程序崩溃,同时也设置了递归调用的退出条件。在写遍历树的代码的时候一定要高度警惕,在每一处需要访问地址的时候都要问自己这个地址有没有可能是NULL,如果是NULL该怎么处理。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
//上述代码中,我们递归调用HasSubtree遍历二叉树A。如果发现某一结点的值和树B的头结点的值相同,则调用DoesTree1HaveTree2,做第二步判断。
bool HasSubtree(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{
bool result = false;
//当Tree1和Tree2都不为零的时候,才进行比较。否则直接返回false
if(pRoot1 != nullptr && pRoot2 != nullptr)
{
//如果找到了对应Tree2的根节点的点
if(Equal(pRoot1->m_dbValue, pRoot2->m_dbValue))
//以这个根节点为为起点判断是否包含Tree2
result = DoesTree1HaveTree2(pRoot1, pRoot2);
//如果找不到,那么就再去root的左儿子当作起点,去判断是否包含Tree2
if(!result)
result = HasSubtree(pRoot1->m_pLeft, pRoot2);
//如果还找不到,那么就再去root的右儿子当作起点,去判断是否包含Tree2
if(!result)
result = HasSubtree(pRoot1->m_pRight, pRoot2);
}
return result;
}
//第二步是判断树A中以R为根结点的子树是不是和树B具有相同的结构。同样,我们也可以用递归的思路来考虑:如果结点R的值和树B的根结点不相同,则以R为根结点的子树和树B肯定不具有相同的结点;如果它们的值相同,则递归地判断它们各自的左右结点的值是不是相同。递归的终止条件是我们到达了树A或者树B的叶结点。参考代码如下:
bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{ //如果Tree2已经遍历完了都能对应的上,返回true
if(pRoot2 == nullptr)
return true;
//如果Tree2还没有遍历完,Tree1却遍历完了。返回false
if(pRoot1 == nullptr)
//此条语句与上条语句不能调换顺序,否则{8,8,7,9,2,#,#,#,#,4,7},{8,9,2}不通过测试
return false;
//如果其中有一个点没有对应上,返回false
if(!Equal(pRoot1->m_dbValue, pRoot2->m_dbValue))
return false;
//如果根节点对应的上,那么就分别去子节点里面匹配
return DoesTree1HaveTree2(pRoot1->m_pLeft, pRoot2->m_pLeft) &&
DoesTree1HaveTree2(pRoot1->m_pRight, pRoot2->m_pRight);
}
bool Equal(double num1, double num2)
{
if(((num1 - num2) > -0.0000001) && ((num1 - num2) < 0.0000001))
return true;
else
return false;
}