链表操作中函数传入链表指针,若根节点没有改变,链表也会改变?

事情是这样的,今天刷剑指offer时,对书中的内容产生了一点点小质疑,所以就拿VS2013和Code::Blocks都跑了一遍,两者结果是一致的,但程序执行的结果让我有点疑惑。
题目如下:
在一个排序的链表中,删除链表中重复的节点。
例如: 1->2->3->3->4->4->5,删除后的结果为1->2->5。
书中说由于头节点也可能被删除,所以函数应申明为
void deleteDuplication(ListNode** pHead)

而不是

void deleteDuplication(ListNode* pHead)
然后我就试了一下第二者,发现如果函数deleteDuplication处理完毕后,如果以形参形式传入的根节点pHead没有发生改变,则在main()函数里打印出链表的时候,链表和处理前的不一样了(即发生了改变);但如果根节点发生了改变,在mian()函数里打印结果却发现链表和处理前一样(即没有发生改变)。
所以我就懵了,按书上这句话的意思,应该就是如果传入的根节点为链表指针(即ListNode* pHead),则链表应该出了函数也不会发生任何变化。
但实际的结果却是由根节点是否发生了变化而决定,求大家赐教哈。
(注:ListNode** pHead是正常的,却是是出了函数也会改变链表实参本身)。
还有一个问题就是如果在函数里delete掉形参链表一个节点,也会影响链表实参本身,这又是什么原理。
完整代码如下:
1)当形参根节点未发生变化时:
#include <stdio.h>
using namespace std;

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
    void deleteDuplication(ListNode* pHead)
    {
        if (pHead == NULL || pHead->next == NULL)
            return;
        ListNode* pNode = pHead;
        ListNode* preNode = NULL;
        while (pNode)
        {
            bool deleteflag = false;
            if (pNode->next && pNode->val == pNode->next->val)
                deleteflag = true;

            if (!deleteflag)
            {
                preNode = pNode;
                pNode = pNode->next;
            }
            else
            {
                int value = pNode->val;
                ListNode* next = pNode;
                while (pNode && pNode->val == value)
                {
                    next = pNode->next;
                    //delete pNode;
                    pNode = next;
                }
                if (preNode == NULL)
                    pHead = pNode;
                else
                    preNode->next = pNode;
            }
        }
    }
};
int main()
{
    //生成链表1->2->3->3->4->4->5
    ListNode* pHead = new ListNode(1);
    pHead->next = new ListNode(2);
    ListNode* pNode = pHead;
    pNode = pNode->next;
    pNode->next = new ListNode(3);
    pNode = pNode->next;
    pNode->next = new ListNode(3);
    pNode = pNode->next;
    pNode->next = new ListNode(4);
    pNode = pNode->next;
    pNode->next = new ListNode(4);
    pNode = pNode->next;
    pNode->next = new ListNode(5);


    Solution so;

    so.deleteDuplication(pHead);
    pNode = pHead;
    while (pNode)
    {
        printf("%d ", pNode->val);
        pNode = pNode->next;
    }
    printf("\n");

    return 0;
}
输出结果如下图:
2)当形参根节点发生变化时:
#include <stdio.h>
using namespace std;

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
    void deleteDuplication(ListNode* pHead)
    {
        if (pHead == NULL || pHead->next == NULL)
            return;
        ListNode* pNode = pHead;
        ListNode* preNode = NULL;
        while (pNode)
        {
            bool deleteflag = false;
            if (pNode->next && pNode->val == pNode->next->val)
                deleteflag = true;

            if (!deleteflag)
            {
                preNode = pNode;
                pNode = pNode->next;
            }
            else
            {
                int value = pNode->val;
                ListNode* next = pNode;
                while (pNode && pNode->val == value)
                {
                    next = pNode->next;
                    //delete pNode;
                    pNode = next;
                }
                if (preNode == NULL)
                    pHead = pNode;
                else
                    preNode->next = pNode;
            }
        }
    }
};
int main()
{
    //生成链表1->1->3->3->4->4->5
    ListNode* pHead = new ListNode(1);
    pHead->next = new ListNode(1);
    ListNode* pNode = pHead;
    pNode = pNode->next;
    pNode->next = new ListNode(3);
    pNode = pNode->next;
    pNode->next = new ListNode(3);
    pNode = pNode->next;
    pNode->next = new ListNode(4);
    pNode = pNode->next;
    pNode->next = new ListNode(4);
    pNode = pNode->next;
    pNode->next = new ListNode(5);


    Solution so;

    so.deleteDuplication(pHead);
    pNode = pHead;
    while (pNode)
    {
        printf("%d ", pNode->val);
        pNode = pNode->next;
    }
    printf("\n");

    return 0;
}
输出结果如下图:

3)当函数中delete掉形参链表的一个节点时
无论形参根节点是否改变,实现链表都会发生变化。且在VS2013下,形参根节点发生改变时,程序会报内存访问出错。
#include <stdio.h>
using namespace std;

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:


    void deleteDuplication(ListNode* pHead)
    {
        if (pHead == NULL || pHead->next == NULL)
            return;
        ListNode* pNode = pHead;
        ListNode* preNode = NULL;
        while (pNode)
        {
            bool deleteflag = false;
            if (pNode->next && pNode->val == pNode->next->val)
                deleteflag = true;

            if (!deleteflag)
            {
                preNode = pNode;
                pNode = pNode->next;
            }
            else
            {
                int value = pNode->val;
                ListNode* next = pNode;
                while (pNode && pNode->val == value)
                {
                    next = pNode->next;
                    delete pNode; //删除当前节点
                    pNode = next; 
                }
                if (preNode == NULL)
                    pHead = pNode;
                else
                    preNode->next = pNode;
            }
        }
    }
};
int main()
{

    ListNode* pHead = new ListNode(1);
    pHead->next = new ListNode(1);
    ListNode* pNode = pHead;
    pNode = pNode->next;
    pNode->next = new ListNode(3);
    pNode = pNode->next;
    pNode->next = new ListNode(3);
    pNode = pNode->next;
    pNode->next = new ListNode(4);
    pNode = pNode->next;
    pNode->next = new ListNode(4);
    pNode = pNode->next;
    pNode->next = new ListNode(5);


    Solution so;
    so.deleteDuplication(pHead);
    pNode = pHead;
    while (pNode)
    {
        printf("%d ", pNode->val);
        pNode = pNode->next;
    }
    printf("\n");

    return 0;
}

#笔试题目#
全部评论
没听懂楼主在说啥 代码也放的太多了 这两个参数一个为ListNode类型的指针,一个为ListNode*类型的指针。 在函数中,为了能够改变对象内部变量的值,需要使用指针/引用类型来进行参数的传递,这是对于一个对象来说的,例中就是指的ListNode。 楼主没理解的应该是,对于ListNode*类型的形参,与普通的变量一样,传递进来的也只是一个副本,而不是原对象的指针,不相信的话可以使用&取地址符号看看传递进函数前后的指针变量的地址是不是一样。所以要想改变指针变量的值,也就是这边删去头结点的情况下,需要使用指向指针的指针来操作。
1 回复 分享
发布于 2019-04-07 15:50
没有仔细看内容,有点长。但是链表是不断指向下一个地址的,如果你在函数里面改变了某个节点的指针指向的地址,那么链表当然会改变,跟根节点有没有改变没关系的。
点赞 回复 分享
发布于 2019-04-07 15:51

相关推荐

冷艳的小师弟在看机会:jd测评乱点直接被挂了,哭死~
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务