第二阶段第二周 数据结构.docx
- 文档编号:24014006
- 上传时间:2023-05-23
- 格式:DOCX
- 页数:16
- 大小:35.81KB
第二阶段第二周 数据结构.docx
《第二阶段第二周 数据结构.docx》由会员分享,可在线阅读,更多相关《第二阶段第二周 数据结构.docx(16页珍藏版)》请在冰豆网上搜索。
第二阶段第二周数据结构
第一天
1、在/etc目录下边有一个environment文件里边存储着环境变量PATH的值
当修改该值之后需要重启一下该文件,则环境变量PATH的值才起作用sudosource/etc/environment
2、线性表
(1)有序表:
元素和元素所在位置之间存在着一定的关系,则是有序表。
3、链表
(1)单链表
(2)双向链表
(3)循环链表
第二天
1、顺序栈
structseqstack{
intiTop;//指向栈顶
intiLen;//栈的最大长度
DataType*pData;//指向存放栈数据的空间
};
2、结构体的不完整类型
typedefstructnode{
inta;
structnode*ptNext;
}tNode;
问:
为什么可以在结构体内部使用structnode*来定义指针,而不能在结构体内部定结构体变量?
答:
structnode*定义的是一个结构体指针变量,该变量是指向这种结构体类型的指针,在结构体内部定义的时候,structnode这种类型还不完整,但是在使用的时候,是知道ptNext指向的是结构体类型。
但是对于变量定义的时候,这种类型不完整,所以定义变量会出错。
在封装自己的函数库的时候,可以使用结构体的不完整类型来实现:
#definestack_tstructstack
第三天
1、链栈的实现
2、链栈实现计算器
算法实现分析:
(1)创建两个栈,一个存储数据,一个存储运算符
(2)根据输入的字符串,将数字提取出来存放在数据栈中
3、链队列
入队:
在头结点处入队
出队:
在尾节点处出队
使用单独的一个结构体structLinkQueueNode来指向对头和队尾;队列数据元素作为另一个单独的结构体。
typedefintDatatype;
typedefstructQueueElement{
Datatypedata;
structQueueElement*ptNext;
}tQueueElement,*tQueueElement_P;
typedefstructLinkQueueNode{
structQueueElement*ptLinkHead;
structQueueElement*ptLinkTail;
}tLinkListQueue,*tLinkListQueue_P;
预习:
1、顺序表实现循环队列:
规定:
入队是从队尾入队Cq_rear
出队是从队首出队Cq_front
为了避免假溢出则入队的条件是Cq_rear=(Cq_rear+1)%max
新对位号 旧队位号 最大队的容量
判断队满的方法:
if((Cq_rear+1)%max == Cq_front)
判断空的方法:
if(front==rear)
第四天
一、循环队列
1、环形缓冲区(循环队列)
注意:
队尾插入,队首删除
(1)入队操作
a、判断队列是否满
b、队列不满,则在队尾插入元素,并且队尾指针加1
cq[rear]=data;
rear=(rear+1)%maxsize
(2)出队操作
a、判断队列是否为空
b、队列不空,则在队首删除元素,并且队首指针加1
data=cq[front];
front=(front+1)%maxsize;
2、循环对列是牺牲一个元素来判定队列为满;
3、队满:
尾追上头
队空:
头追上尾
4、数据结构构造
typedefintDataType;
typedefstructCriQueueNode{
int iFront;
int iRear;
int iMaxSize;
DataType data[0];
}tCriQueue,*tCriQueue_P;
循环总结:
1、队空:
if(iFont==iRear)
2、队满:
if((iRear+1)%iMax==iFont)
3、队列元素个数:
return(iRear-iFont+iMax)%iMax;
二、二叉树
二叉树结构体构造
typedefintDataType;
typedefstructBtreeNode{
intiNum;
DataTypedata;
structBtreeNode*ptLeftChild;
structBtreeNode*ptRightChild;
}tBtree,*tBtree_P;
1、初始化一棵二叉树
/*递归创建一棵二叉树
* 参数iNum:
二叉树结点编号
* 参数iMaxSize:
二叉树的最大容量
**/
tBtree*InitBtree(intiNum,intiMaxSize)
{
tBtree*ptBtree;
if(iNum>iMaxSize) //当结点编号超过了最大容量时,退出递归
returnNULL;
ptBtree=(tBtree*)malloc(sizeof(tBtree));
if(NULL==ptBtree)
returnNULL;
ptBtree->iNum=iNum;
ptBtree->data='a'+iNum-1;
ptBtree->ptLeftChild=InitBtree(2*iNum,iMaxSize); //2n是左子树
ptBtree->ptRightChild=InitBtree(2*iNum+1,iMaxSize); //2n+1是右子树
returnptBtree;
}
2、使用队列层次打印二叉树
队列里边保存的是二叉树节点地址,
a、最先入队根节点的地址
b、如果左右孩子不为空的话,则左右孩子入队
c、孩子入队结束,则双亲节点出队,并且打印数值
d、直到队头和队尾相等时,循环结束
voidPrintBtree(tBtree*root,intiMaxSize)
{
intiHead=0;
intiTail=0;
tBtree*ptBtreeQueue[iMaxSize];
ptBtreeQueue[iTail++]=root;//a
while(iTail!
=iHead) //d
{
if(NULL!
=ptBtreeQueue[iHead]->ptLeftChild)/*左右孩子入队*/ //b
ptBtreeQueue[iTail++]=ptBtreeQueue[iHead]->ptLeftChild;
if(NULL!
=ptBtreeQueue[iHead]->ptRightChild)
ptBtreeQueue[iTail++]=ptBtreeQueue[iHead]->ptRightChild;
/*左右孩子入队结束则双亲节点出队*/ //c
root=ptBtreeQueue[iHead++];
printf("%-5c",root->data);
}
printf("\n");
}
intmain(intargc,constchar*argv[])
{
tBtree*ptBtree;
ptBtree=InitBtree(1,10);
PrintBtree(ptBtree,10);
return0;
}
3、二叉树的三种递归遍历方式
(1)先序遍历TLR
voidTLR_Print(tBtree*root)
{
if(NULL==root)
return;
printf("%-5c",root->data);
TLR_Print(root->ptLeftChild);
TLR_Print(root->ptRightChild);
return;
}
(2)中序遍历LTR
voidLTR_Print(tBtree*root)
{
if(NULL==root)
return;
LTR_Print(root->ptLeftChild);
printf("%-5c",root->data);
LTR_Print(root->ptRightChild);
return;
}
(3)后序遍历LRT
voidLRT_Print(tBtree*root)
{
if(NULL==root)
return;
LRT_Print(root->ptLeftChild);
LRT_Print(root->ptRightChild);
printf("%-5c",root->data);
return;
}
总结:
给出先序和中序序列,就可以完整地画出一棵树
4、二叉树的非递归遍历
(1)先序非递归遍历
原理:
创建一个栈,模仿先序遍历的进栈调用过程。
出栈就是获取右孩子,入栈就是保存左孩子
voidTLR_Stack(tBtree*root)
{
stack_t*tree_stack;
tree_stack=creat_stack(100);
printf("tree_stack:
");
while(!
empty_stack(tree_stack)||NULL!
=root)
{
while(NULL!
=root)
{
printf("%-5c",root->data); //先打印根结点
push_stack(tree_stack,&root); //左孩子一直循环入栈
root=root->ptLeftChild;
}
pop_stack(tree_stack,&root); //出栈是为了获取右孩子
root=root->ptRightChild;
}
printf("\n");
}
(2)中序非递归遍历
原理:
创建一个栈,模仿中序遍历的函数调用进栈调用过程。
出栈就是获取右孩子,入栈就是保存左孩子
voidLTR_stack(tBtree*root)
{
stack_t*tree_stack;
tree_stack=creat_stack(100);
printf("LTR_stack:
");
while(!
empty_stack(tree_stack)||NULL!
=root)
{
while(NULL!
=root)
{
push_stack(tree_stack,&root);
root=root->ptLeftChild;
}
pop_stack(tree_stack,&root);
printf("%-5c",root->data);
root=root->ptRightChild;
}
printf("\n");
}
3、后序遍历非递归实现
原理:
在后序遍历的递归调用的过程中,需要函数调用进栈两次,出栈两次,所以需要一个标志来确定是那一次出栈;
//typedefstructBtreeNode*data_t;
typedefstructdat{
structBtreeNode*root;
intsp_flag;
}data_t;
voidLRT_stack(tBtree*root)
{
stack_t*tree_stack;
data_tDataBuf;
tree_stack=creat_stack(100);
printf("LRT_stack:
");
while(!
empty_stack(tree_stack)||NULL!
=root)
{
while(NULL!
=root)
{
DataBuf.root=root;
DataBuf.sp_flag=1;
push_stack(tree_stack,&DataBuf);
root=root->ptLeftChild;
}
pop_stack(tree_stack,&DataBuf);
if(1==DataBuf.sp_flag)
{
DataBuf.sp_flag=2;
root=DataBuf.root;
root=root->ptRightChild;
//DataBuf.root=DataBuf.root->ptRightChild;
push_stack(tree_stack,&DataBuf);
}
else
{
printf("%-5c",DataBuf.root->data);
}
}
printf("\n");
}
5、完全二叉树的性质
对于有n个结点的完全二叉树,将其所有结点按从上到下、从左到右进行编号,树中任意结点号i(1<=i<=n)那么,
2i>n;没有左子树,否则其左孩子的结点号是2i
2i+1>n;没有右子树,否则其右孩子结点号为2i+1
第五天图、排序和查找
一、三种重要排序
1、冒泡排序
2、快速排序
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:
i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]赋给A[i];
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]赋给A[j];
5)重复第3、4步,直到i=j;(3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。
找到符合条件的值,进行交换的时候i,j指针位置不变。
另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
2排序演示编辑
假设用户输入了如下数组:
下标
0
1
2
3
4
5
数据
6
2
7
3
8
9
∙创建变量i=0(指向第一个数据),j=5(指向最后一个数据),k=6(赋值为第一个数据的值)。
我们取走了下标0的数据,于是,我们需要找到一个数字来替换他。
由于我们要把所有比6小的数移动到左面,所以我们可以开始寻找比6小的数并从右往左找。
别急,我们要按顺序找哦。
不断递减j的值,我们发现下标3的数据比6小,于是把3移到下标0(实际是i指向的位置。
代码中要用i,因为后面还会循环这个步骤,不用i的话第二次循环:
下标
0
1
2
4
5
数据
3
2
7
6
8
9
∙i=0j=3k=6
由于变量k已经储存了下标0的数据,所以我们可以放心的把下标0覆盖了。
如此一来,下标3虽然有数据,但是相当于没有了,因为数据已经复制到别的地方了。
于是我们再找一个数据来替换他。
这次要变成找比k大的了,而且要从前往后找了。
递加变量i,发现下标2是第一个比k大的,于是用下标2的数据7替换j指向的下标3的数据,数据状态变成下表:
下标
0
1
2
3
4
5
数据
3
2
6
7
8
9
∙i=2j=3k=6
重复上面的步骤,递减变量j。
这时,我们发现i和j“碰头”了:
他们都指向了下标2。
于是,循环结束,把k填回下标2里,即得到结果。
如果i和j没有碰头的话,就递加i找大的,还没有,就再递减j找小的,如此反复,不断循环。
注意判断和寻找是同时进行的。
注意:
快速排序不会直接得到最终结果,只会把比k大和比k小的数分到k的两边。
(你可以想象一下i和j是两个机器人,数据就是大小不一的石头,先取走i前面的石头留出回旋的空间,然后他们轮流分别挑选比k大和比k小的石头扔给对面,最后在他们中间把取走的那块石头放回去,于是比这块石头大的全扔给了j那一边,小的全扔给了i那一边。
只是这次运气好,扔完一次刚好排整齐。
)为了得到最后结果,需要再次对下标2两边的数组分别执行此步骤,然后再分解数组,直到数组不能再分解为止(只有一个数据),才能得到正确结果。
代码实现:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第二阶段第二周 数据结构 第二阶段 第二