链表中删除节点引发的思考!!!

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/msdnwolaile/article/details/50785630

1,我们删除链表节点的时候,最常用的就是根据前趋节点,来改变指向,但是如果不用前趋节点,我们能删除吗??

2,在链表中,删除节点的过程中,我们必须调用free函数吗??如果调用,它一定能正确的删除吗??如果不调用free  函数,那么它就一定不会删除吗??

3,一个链表中,如果在输出具体存储的数据之前,我们用其他指针p指向某一个数据,然后我们在将指针p给free掉,会产生什么影响??如果我们free掉p->next,呢??继续free掉p->next->next呢??会产生什么影响???



对与删除链表节点:(我们用简单的程序说明)

程序1:

#include <stdio.h>                                                                                                                              
#include <malloc.h>


typedef struct node{
        
                int data;
                struct node *next;
        }Lnode, *LinkList;

LinkList Creat_LinkList(){
        
                LinkList H = (LinkList)malloc(sizeof(Lnode));
                H->next = NULL;
                Lnode *s;
                int x;
                scanf("%d", &x);
                while(x != -1)
                {
                        s = (LinkList)malloc(sizeof(Lnode));
                        s->data = x;
                        s->next = H->next;
                        H->next = s;
                        scanf("%d", &x);        
                }
                return H;
        }
void  scan_LinkList(LinkList H)
{
        
        LinkList s = (LinkList)malloc(sizeof(Lnode));
        s = H->next;
        while(s!=0)
        {
                printf("%d  ", s->data);
                s = s->next;    
        }
        printf("\n");

}

void delete_LinkList(LinkList p, LinkList H){
        
        LinkList q = (LinkList)malloc(sizeof(Lnode));
        q = H->next;
        if(q == p){
                H->next = H->next->next;
                free(q);
                return ;
        }
        while(q->next != p && q->next != NULL)
                q = q->next;
        if(q->next == p && q->next != NULL)
        {
                q->next = p->next;
                free(p);   
        }
}


int main(){
        LinkList H = (LinkList)malloc(sizeof(Lnode));                                                 //定义指针变量,并且分配内存空间
        H = Creat_LinkList();                                                                                           //创建链表,采用了头插法
        printf("ssssssssssssssssssss\n");                                                                        //便于观察结果
        scan_LinkList(H);                                                                                                 //打印链表,从表头开始
        delete_LinkList(H->next->next->next,H);                                                      //删除第三个元素 H为头节点,H->next指向第一个节点
        printf("aaaaaaaaaaaaaaaaaaaa\n");
        scan_LinkList(H);
        return 0;       
}                                                                                                                                                


如上的delete_LinkList函数:采用的根据前趋节点来删除节点

(引入新的指针变量,作为前趋节点,通过循环q = q->next,来确保q->next == p,也就是q是p的前趋节点,这一中比较常见,大家应该很容易明白!!)(通常情况下需要两层循环,所以时间复杂度也就是O(n^2))

运行结果:

采用无前趋节点的方法

delete_LinkList函数

void delete_LinkList(LinkList p){
        
        p->data = p->next->data;
        p->next = p->next->next;
}

从上面的delete_LinkList函数可以看到,这里的参数跟上次的是不同的(还有主函数中也需要改改),还有重要的一点就是当前的时间复杂度极低,大大的提高效率,但是有的同学可能会疑惑,删除一个链表的节点,咋可能不需要free指针呢,这里程序运行的结果一定有问题???但是,真的是吗??如果,这里我们free一个指针又会产生什么样的问题呢,会得到正确的结果,还是出乎意料的结果呢??

运行结果:


可以看到我们的程序没有一点问题,但是这是为什么呢??这里可是真的没有free指针啊!!!,(按道理来说,这是行不同的啊!!)


如果我们free呢,又会产生什么结果呢???

void delete_LinkList(LinkList p){
        
        p->data = p->next->data;
        p->next = p->next->next;
        free(p);
 }
运行结果:

可以看到本应该出现4的地方,变成了0,啊啊,这是为什么啊!!!(当时一看到这个就快要炸了,为什么啊!!)


后来经过同学的点拨,恍然大悟啊

我们程序两条语句的意思是:要删除第三个节点,我们先将第四个节点指向的内容赋值给第三个节点(p->data = p->next->data;),然后让第三个节点的下一个指向(p->next)指向第五个节点,(p->next = p->next->next)

这里,我们跳过第四个节点,因为第四个节点指向的内容和第三个节点指向的内容是一样的,所以我们不用管第四个节点,访问的时候,可以直接访问第五个节点指向的内容,就间接的达到了删除的目的

而不需要free的原因也很简单,因为此刻第四个节点的内容并没有任何的指针指向,所以也就不能释放了,如果非要释放,可以一开始用一个指针指向过来,值得注意的是:此刻已经不能在free(p)了,因为p指向的并不是我们要删除的节点(此刻,我们要删除的是第四个节点,而p指向的是第三个节点)

其实:不释放的情况下:只是占用了一块内存,但是并不影响函数的目的(删除节点),可能你会觉得不太合理,那我们就来释放一下这个内存吧!!!

释放的情况:

void delete_LinkList(LinkList p){
        LinkList q = (LinkList)malloc(sizeof(Lnode));

        p->data = p->next->data;
        q = p->next;
        p->next = p->next->next;
        free(q);
}

运行结果:

可以看到运行完美,并且多余的内存也被删除掉了


但是,上面的0到底是咋样产生的呢???

仔细分析之后, 觉得:free(p)之后,只是清空了p所指向那块内存的内容(可能因为是第一次free某一块内存,在链表中,所以清空之后,并没有将一个随机值存放到该内存,而是存放了一个0,但是值得注意的是p的地址并没有改变)

,然而,内存还在,所以我们可以通过头指针来完成遍历,并且在输入的时候,输出了一个0(个人理解)



1,我们删除链表节点的时候,最常用的就是根据前趋节点,来改变指向,但是如果不用前趋节点,我们能删除吗??

      可以看出,我们来删除链表节点,可以根据前趋节点,也可以不用前趋节点来删除链表节点,有可能效率更高




2,在链表中,删除节点的过程中,我们必须调用free函数吗??如果调用,它一定能正确的删除吗??如果不调用free  函数,那么它就一定不会删除吗??

从上面可以看出:不一定要调用free函数,如果调用,也不一定能正确删除,有可能导致产生0,如果不调用free函数,那么也会产生正确的结果,正确的删除(但是,此刻有可能还有一个内存块占用内存着呢),当然,如果我们能用其他的一个指针来指向的话,那么也是可以正确删除的,并且还清理了内存块的占用情况!!!




3,一个链表中,如果在输出具体存储的数据之前,我们用其他指针p指向某一个数据,然后我们在将指针p给free掉,会产生什么影响??如果我们free掉p->next,呢??继续free掉p->next->next呢??会产生什么影响???

上面我们已经讨论了free(p)的情况,那么如果我们如果直接释放掉p->next呢??

如下:

void delete_LinkList(LinkList p){

        p->data = p->next->data;
        p->next = p->next->next;
        free(p->next);
}
运行结果:

可以看到我们上面谈到的结论也是正确的


那么如果,我们一起free呢??会产生什么结果??

void delete_LinkList(LinkList p){

        p->data = p->next->data;
        p->next = p->next->next;
        free(p);
        free(p->next);
}
运行结果:

很明显可以看到:输出结果中,出现了0,还出现了垃圾值


那么这样呢??

void delete_LinkList(LinkList p){

        p->data = p->next->data;
        p->next = p->next->next;
        free(p->next);
        free(p);
}
可以很容易的看到:两者释放的顺序不一样,但是结果呢??

运行结果:

看得出来,

当只有一个释放时:清空原有的值,然互给其赋值一个0

当释放多个指针时:不取决谁先释放,而应该是取决于释放的所指向的内容,在链表上的先后顺序吧!!!




展开阅读全文

没有更多推荐了,返回首页