数据结构学习有感

杂谈

这两天已经开始看数据结构了,尽管c语言还是懵懵懂懂。我学习的课本是 严蔚敏老师的《数据结构》(c语言版)。其实我数买了一段时间,但是一直摸有开始,原因很简单,看不懂结构体。经常看到一大堆莫名其妙的引用 访问什么的,瞬间头大。所以我就抽时间去吧结构体学了一下。 学完结构体我寻思着,可以看看看数据结构了吧,我还是太年轻了。
数据结构 主要是数据和数据之间的关系 以及存储形式(我目前的认知)。单说书上的结构,概念其实很简单,数据之间的关系一讲其实也就全都明白了。但是,我觉得这本书确实有点难学。因为书上有很多算法知识(我的感觉)。我们把数据 和数据之间的关系用特定的方式存储进来,要实现某种目标,就必须用某种方法来对这些数据进行有效的推导、计算、剖析等。就拿一个很简单的 表达式求值来说。要用栈结构,这个我知道,但是如何把表达式存入,又如何取出,最后又如何计算呢?他并不是无脑的读一个、压一个。书上的例子卸载哪里,我却看不懂,最后去问百度爸爸,才知道中间涉及到一个中缀转后缀的过程。还有一道书上的字符串模式匹配的例子。

那个next数组的求法,以及意义很简单,我可以通过手工算出来,无非就是字符串前缀模式和后缀模式相同时最大字符串长。

但是如何通过编程让机器去运算的。 我逐渐发现,一旦将某些简单问题的规模扩大化,虽然原始的解决方法同样适用,但是从计算成本上来就显得并不合适。我们就需要通过某种具有数学归纳思想的解决办法,将同种问题不同规模的解决办法归纳成一个模板。最后只要套用模板,由计算机去代替人力运算,就能得到结果。

这个模板就是我所理解的泛型

而对复杂问题的巧妙解决中间所涉及的数学思想,逻辑能力就是我目前所认知的算法。

结构体

学习数据结构就必须要对结构体有一个基本的掌握。因为在往常的数据类型中,并没有一种结构能够包含多种不同类型数据。而数据结构,主要是数据和数据之间的关系,而实际情况看往往是复数、复杂、的数据之间相互关联。所以结构体就是数据结构的首选,结构体就是数据结构的基本组成单位(我的个人理解)。

结构体声明

关键字 struct + 类型名称
{
内部数据类型(数组 、int、char、等)
}+变量名;

例如
定义一个学生的基本信息结构体

typedef struct Stu
 { 
   char name[20];//名字  
   int age;//年龄   
   char sex[5];//性别 
   char id[20]//学号 
}Stu2;//分号不能

结构体 的类型名称(struct 后面的变量名 例如 struct Stu中的Stu)可以省略。结构体变量的变量名称也可以省略。(例如上述的Stu2)但是两者必须要有一个。

结构体成员访问

结构体成员访问有两种访问方式。一种是结构体变量名称.访问成员一种是结构体指针->访问成员

扫描二维码关注公众号,回复: 9414727 查看本文章
struct Stu {
    char name[20]; 
    int age; 
}*ps;

(*ps).name     (*ps).age; 

 ps->name,       ps->age ; 

结构体中可以嵌套结构体,访问嵌套结构体时,按照上述规则访问即可。

结构体传参

结构体传参和数组传参不一样

数组传参会发生降维问题。但是结构体不会发生。
结构体在传参时,如果传入的实参时结构体变量时,,在发生形参实例化时,会发生结构体全拷贝。并不会和数组一样降维成对应的指针。
传入结构体实参会发生全拷贝,造成不必要的内存耗费,既然上述已经说过结构体成员的访问形式有两种,指针也可以对结构体进行成员访问,切指针在传参时,哪怕发生拷贝,拷贝的也只是一个指针大小,并不会造成内存的浪费。所以在大多数情况下结构体传参一般传入的都是结构体指针。

内存问题

数据结构中很多内存都是在堆上开配的空间,很多时候都会用到开辟内存的函数

melloc函数

其函数原型为void *malloc(unsigned int size);其作用是在内存的动态存储区中分配一个长度为size的连续空间。此函数的返回值是分配区域的起始地址,或者说,此函数是一个指针型函数,返回的指针指向该分配域的开头位置。

在使用melloc函数时元注意,我们需要对melloc函数的返回值进行强制类型转换。如果不做强制类型转换的话,返回的指针和需要的指针类型不一样,就会对访问造成影响。并且如果有后续的存储操作一般都需要对melloc函数的返回值进行判断避免开辟空间失败的情况。

relloc函数

realloc(void *__ptr, size_t __size):更改已经配置的内存空间,即更改由malloc()函数分配的内存空间的大小。

如果将分配的内存减少,realloc仅仅是改变索引的信息。

如果是将分配的内存扩大,则有以下情况:

1)如果当前内存段后面有需要的内存空间,则直接扩展这段内存空间,realloc()将返回原指针。
2)如果当前内存段后面的空闲字节不够,那么就使用堆中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据块释放掉,返回新的内存块位置。
3)如果申请失败,将返回NULL,此时,原来的指针仍然有效。

原文链接:https://blog.csdn.net/hackerain/article/details/7954006

其中第二点是先在堆上找到一段空闲内存,开辟需求内存扩大之后的空间。然后将原来那段内存中的数据完全 copy过来。最后原来那段空间会自动释放,并不需要手动free

free函数

C 库函数 void free(voidptr)* 释放之前调用 calloc、malloc 或 realloc 所分配的内存空间 [1] 。

free函数看起来很简单。但是在实际使用过程中,书上一般会先声明一个和目标指针相同类型的结构体指针,然后对这个新声明的结构体指针进行赋值(将目标指针作为右值)。最后再由free函数释放。
例如

struct  A *a//定义一个新的结构体指针
a=b//b为目标指针
free(a);

一般都是这种形式的释放。至于为什么要这样我到现在也不是很懂。

melloc函数开辟的动态内存一般都要通过free函数释放。如果不释放就会造成内存泄漏的问题。
同时melloc函数free函数中所有指针类型一定要统一(melloc函数返回指针要进行强制类型转换,free函数的实参指针类型一定要统一)

以上就是我近期的学习想法。可能有很多错误,希望大佬们指正

发布了13 篇原创文章 · 获赞 13 · 访问量 749

猜你喜欢

转载自blog.csdn.net/jiewaikexue/article/details/103498594