• 链表删除结点的一次错误记录


    链表删除结点

    题目描述

    输入一个正整数repeat(0 < repeat < 10),做repeat次下列运算:
    输入一个正整数n(0 < n < 10)和一组( n 个 )整数,建立一个单向链表
    再输入一个整数x,将链表中最后一个与x相等的整数删除。

    输入格式

    见输入样例

    输出格式

    见输出样例

    输入样例

    3       
    5
    1 2 4 3 7
    4
    5
    2 1 5 7 5
    5
    3
    1 2 4
    100
    

    输出样例

    size=4:1 2 3 7
    size=4:2 1 5 7
    size=3:1 2 4
    

    思路

    创建一条单向链表,因为题目要找出并删除最后一个与x相同的数,所以反转链表,删除第一个与x相同的数,这样就不用做标记,删除后再反转一次,最后输出。

    #include<stdio.h>
    #include<stdlib.h>
    int flag;
    struct Node{
    	int num;
    	struct Node *next;
    };
    
    struct Node *Create(int n)   //创建链表
    {
    	struct Node *current,*prev;
    	struct Node *head = NULL;
    	int cnt = 0;
    
    	while (cnt != n)
    	{
    		current = (struct Node *)malloc(sizeof(struct Node));
    
    		scanf("%d",&current->num);
    
    		if (head == NULL)
    		    head = current;
    		else
    		    prev->next = current;
    		prev = current;
    		cnt++;
    	}
    	prev->next = NULL;
    	return head;
    }
    
    void Print(struct Node *head)  //打印链表
    {
    	struct Node * current;
    	current = head;
    
    	printf("%d",current->num);
    	current = current->next;
    	while (current != NULL)
    	{
    		printf(" %d",current->num);
    		current = current->next;
    	}
    	printf("
    ");
    }
    
    struct Node *Reverse(struct Node *head)  //反转链表
    {
    	struct Node *current,*prev,*tmp;
    
    	current = head;
    	prev= current->next;
    	while (prev != NULL)
    	{
    		tmp = prev->next;
    		prev->next = current;
    		current = prev;
    		prev = tmp;
    	}
    	head->next = NULL;
    	head = current;
    	return head;
    }
    
    struct Node *Delete(struct Node *head,int num)  //删除特定结点
    {
    	struct Node *current;
    	struct Node *prev;
    
    	current = head;
    
    	while (current->num != num && current->next != NULL)
    	{
    		prev = current;
    		current = current->next;
    	}
    
    	if (current->num == num)
    	{
            if (head == current)
            {
            	head = current->next;
            }
            else
            {
            	prev->next = current->next;
            }
    	}
    	else
    	{
    		flag = 0;
    	}
    
    	return head;
    }
    
    
    int main()
    {
    	int N,repeat,x;
    	struct Node *head;
    
    	scanf("%d",&repeat);
    
    	while (repeat--)
    	{
    		flag = 1;
    		scanf("%d",&N);
    		head = Create(N);
    		scanf("%d",&x);
    		head = Reverse(head);
    		head = Delete(head,x);
    		head = Reverse(head);
    		if (flag)
    		   printf("size=%d:",N-1);
    		else
    		   printf("size=%d:",N);
    		Print(head);
    	}
    
    	return 0;
    }
    

    后来在和同学讨论的时候发现自己忘了释放内存,之后就补了Free函数

    void Free(struct Node *head)
    {
    	struct Node *current;
    
    	current = head;
    
    	while (current != NULL)
    	{
    		free(current);
    		current = current->next;
    	}
    }
    

    但是在添加Free函数调用它的时候主函数中只repeat了一次,没有再次进入while(repeat--)中,回看代码看了很久都没发现错误,除Free函数各模块代码都没有错,因为之前没有Free函数时都可以正常的输出。之后调试了一下程序,发现程序一直停止在

    Free(head);
    

    这个语句。问了下学姐,提醒我打出current地址,尝试打印了一下Free函数里面current变量的地址值

    地址五个一次循环,难怪一直没有第二次进入while循环。但是在Free函数里面也没发现错误。最后求助了学长,学长说在Free函数里面,free掉current后又用到了current的值导致出错。然后我就尝试着修改了一下

    while (current != NULL)
    	{
    		tmp = current;
    		free(current);
    		current = tmp->next;
    	}
    

    运行之后还是老样子,想了很久没发现逻辑上的问题,学长学姐提点了一下,tmp和current指向同一个内存区,然后又free掉了,所以tmp最后也指向了不明内存区,跟第一次犯的错误根源上一样。现在也慢慢发现对于指针的内涵还是不是很懂。最后改成如此

    void Free(struct Node *head)
    {
    	struct Node *current,*tmp;
    	
    	current = head;
    	
    	while (current != NULL)
    	{
    		tmp = current->next;
    		free(current);
    		current = tmp;
    	}
    } 
    

    附上大神本题另一种解法:

    #include <cstdio>
    using namespace std;
    struct Node{
    	int val;
    	Node *next; 
    }	tab[10086];
    Node *p[10086];
    
    int  n,repeat;
    int  i,j,k,x;
    
    int main()
    {
    	
    	scanf("%d",&repeat);
    	
    	
    	for(j=0; j<repeat; j++)
    	{
    		scanf("%d",&n);
    		
    		for (i=0; i<=20; i++) p[i]=&tab[i];
    		//--1 read 
    		for (i=1; i<=n; i++)
    		{
    			scanf("%d",&p[i]->val);
    			p[i-1]->next=p[i];
    		}
    		p[n]->next=NULL;
    	
    		//--2 search x
    		scanf("%d",&x);
    		Node *tmp=NULL;
    		for (Node *tai=p[0]->next; tai!=NULL; tai=tai->next)
    			if (tai->val==x) tmp=tai;
    	
    		//--3 delete tmp
    		for (Node *tai=p[0]; tai!=NULL; tai=tai->next)
    		if (tai->next!=NULL)
    		if (tai->next==tmp)
    		{
    			tai->next=tai->next->next;
    			n-=1;
    		}
    	
    		//--4 Print
    		printf("size=%d:",n);
    		for (Node *tai=p[0]->next; tai!=NULL; tai=tai->next)
    		{
    			printf("%d",tai->val);
    			n-=1;
    			if(n>0) printf(" ");
    		}
    		
    		if (j<repeat-1) printf("
    ");
    	}
    	return 0;
    }
    

    总结

    虽然在线提交的时候,数据点测试通过,但是没有考虑指针,通过简单的一个Free函数,折腾了好久,也错了很多次,但也因此更了解指针
    **指针的理解与应用仍需加强啊 **

  • 相关阅读:
    (转)MVC 与三层架构
    (转)CentOS一键安装Nginx脚本
    (转)Python异常类的继承关系
    CMFCPropertyGridProperty用法
    C语言终极面试及答案分析
    C/C++函数指针(typedef简化定义)
    UNIX 家族及Linux
    Socket的综合应用总结
    Socket模型(二):完成端口(IOCP)
    socket通信中select函数的使用和解释
  • 原文地址:https://www.cnblogs.com/ZhaoxiCheung/p/5303121.html
Copyright © 2020-2023  润新知