链表删除结点

题目描述

输入一个正整数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("\n");
}

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("\n");
    }
    return 0;
}

总结

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

PTA 链表删除结点的题目测试的更多相关文章

  1. pta 奇数值结点链表&&单链表结点删除

    本题要求实现两个函数,分别将读入的数据存储为单链表.将链表中奇数值的结点重新组成一个新的链表.链表结点定义如下: struct ListNode { int data; ListNode *next; ...

  2. leetCode:237 删除链表的结点

    删除链表的结点 编写一个函数,在给定单链表一个结点(非尾结点)的情况下,删除该结点. 假设该链表为1 -> 2 -> 3 -> 4 并且给定你链表中第三个值为3的节点,在调用你的函数 ...

  3. 237 Delete Node in a Linked List 删除链表的结点

    编写一个函数,在给定单链表一个结点(非尾结点)的情况下,删除该结点. 假设该链表为1 -> 2 -> 3 -> 4 并且给定你链表中第三个值为3的节点,在调用你的函数后,该链表应变为 ...

  4. 数据结构:链表 >> 链表按结点中第j个数据属性排序(冒泡排序法)

    创建结点类,链表类,测试类 import java.lang.Object; //结点node=数据date+指针pointer public class Node { Object iprop; p ...

  5. A Magic Lamp---hdu3183(链表删除| RMQ)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3183 给你一个长度<1000的数a,和m<len(a); 让把数a删除m个数字之后剩下的数 ...

  6. 删除Oracle Online Redo 测试

    删除Oracle Online Redo 测试 SQL> select * from v$log; ​   GROUP#   THREAD# SEQUENCE#     BYTES BLOCKS ...

  7. xml解析-jaxp删除结点

    jaxp删除结点 / 删除sex结点 * 1.创建解析器工厂 * 2.根据解析器工厂创建解析器 * 3.解析xml返回document * * 4.得到sex结点 * 5.得到sex的父节点 getP ...

  8. C语言:将字符串中的字符逆序输出,但不改变字符串中的内容。-在main函数中将多次调用fun函数,每调用一次,输出链表尾部结点中的数据,并释放该结点,使链表缩短。

    //将字符串中的字符逆序输出,但不改变字符串中的内容. #include <stdio.h> /************found************/ void fun (char ...

  9. LeetCode 876. Middle of the Linked List(获得链表中心结点)

    题意:获得链表中心结点.当有两个中心结点时,返回第二个. 分析:快慢指针. /** * Definition for singly-linked list. * struct ListNode { * ...

随机推荐

  1. 用js转换joson返回数据库的时间格式为/Date(*************)/

    原理是取中间的毫秒数,再转换成js的Date类型 function ChangeDateFormat(val) { if (val != null) { var date = new Date(par ...

  2. windows部署React-Native的开发环境实践(技术细节)

    前情摘要 众所周知,有人说.net可以用Xamrian,呵呵,不习惯收费的好么?搞.Net的人设置一次java的环境变量,可能都觉得实在太麻烦了,可能是因为这些年微软确实把我们给带坏了,所有东西一键安 ...

  3. (六)观察者模式详解(包含观察者模式JDK的漏洞以及事件驱动模型)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 本章我们讨论一个除前面的单例 ...

  4. Java序列化中的SerialVersionUid

    版权声明:本文为博主fbysss原创文章,转载请注明出处 作者:fbysssmsn:jameslastchina@hotmail.com  blog:blog.csdn.NET/fbysss声明:本文 ...

  5. CSS 问题集锦

    [1]让DIV中的内容居中 1.文字垂直居中,关键代码:height:100px;line-height:100px(两个值要相等) <div style="margin:0 auto ...

  6. AlertDialog之常见对话框(单选对话框、多选对话框、进度条对话框)

    单选对话框,顾名思义就是只能选一项(setSingleChoiceItems(Items,)) public void click(View v){ //创建对话框类 AlertDialog.Buil ...

  7. Cadence 建立封装:多个引脚于芯片内部连接的封装建立方式

    Ti 家有一种片子,型号为CSD19534Q5A.此芯片的外观样式如图: 可以看到,这个片子共有8个引脚,其中5.6.7和8这四个引脚的内部是连接在一起的. Ti 在数据手册中也介绍了封装的样式: 下 ...

  8. iOS 监听textfield的输入(转)

    1:首先 [textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEvent ...

  9. 二叉树的建立与递归遍历C语言版

    </pre><pre name="code" class="cpp">#include <stdio.h> #include ...

  10. [转]Servlet 中文乱码问题及解决方案剖析

    原文地址:http://blog.csdn.net/xiazdong/article/details/7217022/ 一.常识了解 1.GBK包含GB2312,即如果通过GB2312编码后可以通过G ...