郝斌数据结构笔记

1、时间复杂度:大概程序要执行的次数,而非执行的时间。

2、算法的标准:时间复杂度,空间复杂度,难易程度,健壮性

3、字段 记录 表

4、A a1=new A() :a保存了A在堆里面的地址
A a2=a1: a1地址赋给a2
a1.f():a1指向对象

5、指针 结构体 动态内存的分配与释放

6、int *P:P是个指针变量,int *表示该P变量只能存储int类型变量的地址

7、地址:内存单元的编号 从0开始的非负整数

8、算法:
狭义的算法是与数据的存数方式密切相关
广义的算法是与数据的存储方式无关
泛型:利用某种技术达到的效果就是:不同的存数方式,执行操作都是一样的

地址线 32位 4g-1(2的32次方)
控制线
数据线

指针就是地址 地址就是指针
指针变量就是存放内存单元地址的变量
指针的本质就是一个操作受限的非负整数

8、分类:
基本类型指针


指针和数组的关系

数组名:一维数组名是一个指针常量
它存放的是一维数组第一个元素的地址
它的值不能被改变
一维数组名指向的是数组的第一个元素
下标与指针的关系:
a[i]==*(a+i)

9、
指针初始化时,“=”的右操作数必须为内存中数据的地址,不可以是变量,也不可以直接用整型地址值(但是int*p=0;除外,该语句表示指针 为空)。此时,*p只是表示定义的是个指针变量,并没有间接取值的意思。

如果:int *p;
*p = 7;
则编译器(vs2008)会提示The variable 'p' is being used without being initialized.即使用了未初始化的变量p。
因为p是指向7所在的地址,*p = 7给p所指向的内存赋值,p没有赋值,所以p所指向的内存位置是随机的,没有初始化的。


10、double 占8个字节 1个字节占8位 1个字节就是1个地址
double x=10.2
p=&x p存放的是第一个字节的地址(首地址)

11、指针变量统一只占4个字节。用变量的地址使用第一个字节来表示整个变量的地址

12、改变变量-->通过地址改写值

13、类是一种数据类型

14、结构体是一种用户自定义的数据类型

15、地址总线是32根线 有2种状态:1和0 可以存2的32次方所以内存是4g “1”

16、如何使用结构体:
两种方式:
struct Student st={1000,"zhangsan",20}
struct Student * pst= &st;
1. st.sid
2. pst->sid=*pst.sid;

pst所指向的结构体变量中的sid这个成员

注意事项:结构体变量不能加减乘除只能相互赋值

17、动态分配内存,除了手动释放,只有到程序结束才能释放

18、线性结构
连续存储:数组
离散存储:链表
线性结构

两种常见应用:栈 、队列(时间有关)
19、链表:n个节点离散分配
彼此通过指针相连
每个节点只有一个前驱节点,每个节点只有一个后续节点
首节点没有前驱节点 尾节点没有后续节点

专业术语:
首节点
尾节点
头结点 无存放有效数据,也无存放个数,目的是为了方便对链表的操作
头指针 指向头结点的指针变量
尾指针


20、确认一个链表的参数:头结点地址(头指针)通过头指针可以推算出链表的其他所有参数
确定一个数组的参数:首地址、长度、有效个数

21、头结点与后面的数据类型一致
不同链的头结点字节数不一样

22、每个节点数据类型一样;分两部分:有效数据、指针域
每个节点的指针域指向下一个节点的整体部分

23、链表的分类:单链表
双链表:每一个结点有链表都有两个指针域
循环链表:能通过任意一个结点找到其他结点
非循环链表
24、算法:
遍历
查找
清空
销毁
求长度
排序
删除节点
插入节点

25、链表插入伪算法:p q (指针变量)
q->pNext = p->pNext;表示指向p的下一个节点,因为p->pNext存放的下一个节点
p->pNext = q;(2句倒过来错误)

26、链表删除伪算法:p->pNext=p->pNext->pNext (但是会导致内存泄露,无法找到p->pNext,所以不行)

r=p->pNext;
p->pNext=p->pNext->pNext
free(r);
只能如上所写

如果一开始直接free p->pNext则就无法找到p->pNext->pNext
如果最后free 但是p->pNext已经找不到了内存泄露(越用越少)

27、算法:狭义的算法是与数据的存储方式密切相关
广义的算法是与数据的存储方式无关
泛型:利用某种技术达到的效果就是:不同的存数方式,执行的操作是一样的

28、数据结构
狭义就是专门数据存储的问题
数据的存储包含两方面:个体的存储+个体关系的存储


广义就是既包含数据的存储也包含数据的操作
对存储数据的操作就是算法
29、
数据的存储结构:

线性:

连续存储【数组】
优点:存储速度很快
缺点:插入删除很慢(需要移动元素位置,插入删除元素的效率极低)
空间通常是有限制
事先必须知道数组的长度
需要大块的连续的内存块



离散存储【链表】
优点:空间没有限制
插入删除元素很快
缺点:存储速度很慢

线性结构的应用:栈 队列

非线

性:




30、静态内存在栈里面分配的
动态内存在堆里面分配的

int *p(栈分配)=(int *)malloc(100)(堆分配);
栈堆分配数据的一种方式
静态、局部变量进栈压栈的方式
动态变量堆排序

31、栈:一种可以实现“先进后出”的存储结构;
栈类似于箱子

32、栈的分类:静态栈
动态栈

33、栈的算法:

出栈:
压栈:

34、
青年医生

ponping

35、循环队的入队算法如下:
1、rear=(rear+1)%数组的长度
即rear=n+1,则rear=1;
2、若front=rear尾指针与头指针重合了,表示元素已装满队列,则作上溢出错处理;
3、否则,Q(rear)=X,结束(X为新入出元素)。

36、判断是否为空:判断rear和front是否相等,相等则为空

37、判断是否已满:if(r+1)%数组长度==f)已满 else 不满

38、队列的具体应用:所有和时间和有关的操作都与队列相关

39、当一个函数的运行期间调用另一个函数时,在运行被调函数前,系统需要完成三件事:
(1)将所有该的实际参数,返回地址等信息传递给被调函数保存
(2)为被调函数的局部变量(包括形参)分配存储空间
(3)将控制转移到被调函数入口

40、从被调函数返回主调函数之前,系统也要完成三件事:
(1)保存被调函数的返回结果
(2)释放被调函数所保存的存储空间
(3)依照被调函数保存的返回地址将控制转移到被调函数

41、当有多个函数相互调用时,按照“先调用后返回”的原则上述函数之间的信息传递和控制转移必须借助栈俩实现,即系统将整个程序运行时所需的数据空间安排在一个栈中,每当调用一个函数时,就在栈顶分配一个存储区,进行压栈操作,每当一个函数退出时,就释放它的存储区,就进行出栈操作,每当运行的函数永远都在栈顶位置

42、A函数调用A函数和A函数调用B函数没有区别

43、递归要满足三个条件:
1、递归必须要有一个明确的中止条件
2、该函数所处理的数据规模必须在递减
3、这个转化必须是可解的

44、递归:易于理解 速度慢 存储空间大
循坏:不易理解 速度快 存储空间小


45、树:
1、有且只有一个称为根的节点
2、有若干个互不相交的子树,这些子树本身也是一棵树

节点 父节点 子节点
子节 堂兄弟
深度:
从根节点到最底层节点的层数称之为深度

46、二叉树的存储:
连续存储[完全二叉树]、链式存储


47、完全二叉树的存储
优点:查找某个节点的父节点和子节点(也包括判断有没有子节点


缺点:耗用内存过大

48、链式存储 分三部分(左边连左孩子、中间存值、右边连右孩子(或者多一个父))


49、一般树的存储:
双亲表示法:
一个数组存父节点下标;求父节点方便
孩子表示法:
数组不存下标;存指针域; 求子节点方便
双亲孩子表示法:
数组+链表的方式存储;求子节点和父节点都很方便
二叉树表示法:

把一个普通树转化为二叉树存储:
设法保证任意一个节点
左指针域指向他的第一个孩子节点
右指针域指向它的兄弟节点
只要满足此条件,就可以把一个普通树转化为二叉树


50、一个普通树转化成的二叉树一定没有右子树

51、森林的存储:先把森林转化为二叉树,再存储二叉树

52、树的遍历:
遍历:
先序遍历:(先访问根节点)
先访问根节点
再先序访问左子树
再先序访问右子树

中序遍历:(中间访问根节点)
中序先访问左子树
再访问根节点
再中序访问右子树

后序遍历:(最后访问根节点)
中序先访问左子树
再中序访问右子树
再访问根节点


53、已知两种遍历序列求原始二叉树

54、哈希表

55、泛型:
同一种逻辑结构(例如线性结构),无论该逻辑结构物理存储是什么样 我们对可以对它执行相同的操作


56、已知先序和中序 或者 中序和后序 可以推算出原始二叉树
但是已知 先序和后序 是无法还原出原始的二叉树










相关文档
最新文档