C语言——写单链表代码及感悟

一、代码

 

#include 
#include 
struct listnode
{
    char data;
    struct listnode* nextnode;
};
struct listnode* tail_creat()//尾插法
{
    struct listnode *p, *head, *s;
    char ch;
    head = NULL;
    p = NULL;
    printf("请输入要插入的字符");
    ch = getchar();
    while (ch != '\n')
    {
        s = (struct listnode *)malloc(sizeof(listnode));
        if (s != 0)
        {
            s->data = ch;
            s->nextnode = NULL;
            if (head == NULL)
            {
                head = s;
                p = s;
            }
            else
            {
                p ->nextnode = s;
                p = s;
            };
        };
        ch = getchar();
    }
    return head;
}
struct listnode* head_creat()//头插法
{
    struct listnode* head;
    char ch;
    struct listnode* s;
    head = NULL;
    printf("请输入要插入的字符:");
    ch = getchar();
    while (ch != '\n')
    {
        s = (struct listnode*)malloc(sizeof(struct listnode));
        s->data = ch;
        s->nextnode = head;
        head = s;
        ch = getchar();
    };
    return head;
};
struct listnode* insert(struct listnode *h)//插入
{
    struct listnode *head, *p, *q;
    head = NULL;
    p = NULL;
    q = NULL;
    int n;
    struct listnode* s;
    s = (struct listnode *)malloc(sizeof(listnode));
    if (s != NULL)
    {
        char c;
        printf("请输入要插入的位置:");
        scanf_s("%d", &n);
        printf("请输入要插入的字符:\n");
        getchar();

        c = getchar();
        while (c != '\n')
        {
            s->data = c;
            s->nextnode = NULL;
            c = getchar();
        }
        head = h;
        p = h;
        q = h;
        if (n <= 1)
        {
            s->nextnode = head;
            head = s;
        }
        else
        {
            for (int i = 1; i <= n - 1; i++)
            {
                if (q == NULL)
                {
                    break;
                }
                else 
                {
                    p = q;
                    q = q->nextnode;
                }
            }
            if (q != NULL)
            {
                s->nextnode = q;
                p->nextnode = s;
            }
            else
                p->nextnode = s;
        };
    }
    return head;
};

struct listnode* dele(struct listnode *h)//删除
{
    struct listnode *head, *p, *q;
    head = NULL;
    p = NULL;
    q = NULL;
    int n;
    printf("请输入要删除的位置:");
    scanf_s("%d", &n);
    head = h;
    p = h;
    q = h;
    if (n <= 1)
    {
        head = h->nextnode;
        free(h);
    }
    else
    {
        for (int i = 1; i <= n - 1; i++)
        {
              if (q == NULL)
              {
                    break;
              }
              else
              {
                    p = q;
                    q = q->nextnode;
              }
        }
        if (q != NULL)
        {
            p->nextnode = q->nextnode;
            free(q);
        }
        else
        {
            printf("不存在%d个点\n", n);
        }
    }
    return head;
}
void tranversal(struct listnode *h)//遍历
{
    struct listnode *p, *q;
    p = h;

    printf("输出:");
    while (p)
    {
        printf("%c",p->data);
        q = p->nextnode;
        free(p);
        p = q;
    };
};
struct listnode*reverse(struct listnode* h,int n)//倒序
{
    if (n > 1)
    {
        struct listnode*p, *q,*r, *s,*head;
        head = h;
        p = h;
        q = p->nextnode;
        r = head;
        s = q->nextnode;
        for (n; n > 1; n--)
        {
        
            for (int i = n - 1; i > 0; i--)
            {
                p->nextnode = NULL;
                q->nextnode = NULL;
                p->nextnode = s;
                q->nextnode = p;
                if (i == n - 1)
                {
                    
                    head = q;
                    r = head;
                }
                else 
                {
                    r->nextnode = q;
                    r = r->nextnode;
                }
                
                if (s != NULL)
                {
                    s = s->nextnode;
                    q = p->nextnode;    
                }
            }
            p = head;
            q = p->nextnode;
            r = head;
            s = q->nextnode;
        }
        return head;
    }
    else 
    {
        struct listnode* hd;
        hd = h;
        return hd;
    }
}
int main()
{
    struct listnode *hd1,*hd2;
    hd1 = tail_creat();
    printf("请输入链表长度:");
    int n;
    scanf_s("%d", &n);
    hd2 = reverse(hd1,n);
    tranversal(hd2);
    getchar();
    char c = getchar();
    return 0;
}


二、感悟:

/*记写单链表的几点体验和待改进的地方:
体验和感悟:1.链表和顺序表的不同:可以理解为都是由数据和地址构成的,顺序表的地址对应索引,
            一个索引指向一个数据,而链表的地址对应指针,一个指针指向的是一个链表即一串数
            据;
            2.getchar()的用法:从标准输入一次读取多个字符(遇到\n则刷新)到缓存;调用
            getchar()可从缓存读取一个字符,如果在处理时,使用了while (getchar()!= '\n'),
            则在下次使用getcar()从标准输入读取时,应先使用getchar()取走缓存中的“\n”;
            3.printf字符串的格式:printf(%s,zifuchuan;
            4.scanf_s相比scanf更安全:可防止缓冲区溢出;
            5.NULL要大写;
            6.在设计一些解决方案时可参考已有的、相似的、成熟的算法:如单链表的倒叙我参考了
            冒泡排序;写代码时的语法也有参考冒泡排序
            7.typedef和define的区别:一个是起别名,一个是预编译时的替换;还有
            typedef struct L{……} l:struct L{……}是一个具体的结构的数据类型,l是起的别名;
            在结构体的定义中,倘若需要定义该结构体本身的指针,则需要用struct L* p,因为还没完
            成typedef的定义,故此时不能直接使用别名l;
            8.在malloc分配了地址后,要去检查一下再使用;避免分配失败引起麻烦;
待改进的地方:1.注释和代码风格需要规范;
              2.调试时需要理清当前问题是什么,当前现象是什么,再考虑如何解决,否则代码改着
              改着自己也思维混乱了;
              3.在着手写时,考虑清楚该类与其他同类的共性及个性,也许会避免一些意外的调试结果;
              4.以后在设计解决方式时,应考虑到性能:空间复杂度和时间复杂度;*/

三、学习:

A、写代码的好习惯:(目前还get不到点)
1.编程好习惯之变量定义:
    定义变量时总是按变量类型所占空间大小来排序是最好的!
    如果是只有某个函数使用些变量,而且你又需要在函数让函数退出时不被销毁,那么就使用static吧
2.编程好习惯之函数定义:
    如果我们定义的C函数仅在此C文件中被调用那么加上static吧(适用于多文件编程)
          如果我们想躲避C函数参数的类型检查,那 么K&R的函数定义声明方式还是很不错的!
3.编程好习惯之变量类型使用
    如果我们考虑可移植性的化,就最好不要去乱用int变量,因为int在不同的平台和编译器上是变化的!
4.编程好习惯之编码
    有时间在不明显减少代码的可读性时,可以考虑将一些语句合并,使编译器充分使用寄存器,
    当然如果使用register 变量作中间变量效果也是一样的!
    对于一些频繁使用的变量可以考虑使用寄存器变理,如for语句中使用的变量,这样可以获得更快的速度,但是要注意的是,这个变量的使用范围一定要非常的小才可以使用        寄存器变量!
    尽量使用逻辑运算代替算术运算
5.在使用类似 a &= 0xfff7 来清除某一位时,不妨试试 a &= ~(1 << 4),即不会影响效率,编译器还会帮你确定到底是使用a &= 0xffffff7 还是在高位有更多个ff.
6.宏名有效范围仅限于本c源文件
7.如果要清除某个标志位,或许直接清除,这样比先判断再清除要快得多

8.通过设计规划尽量做到模块独立;

9.边写边编译可以降低调试难度;

10.注释:模块描述、头文件描述、函数描述

模块描述中应该包括,版本号、生成日期、作者、内容、功能、与其它文件的关系、修改日志等等;

头文件一般包含了数据结构的定义,函数原型的说明,宏定义等等,不许包含函数体和变量实体,文件名使用缺省的后缀.h;

函数的头部应进行注释,列出:函数的目的/功能、输入参数、输出参数、返回值、调用关系等

还有一篇参考:http://blog.sina.com.cn/s/blog_4a4593220100n907.html

你可能感兴趣的:(linux,c,data,structure,C)