福建专升本数据结构讲解.docx
- 文档编号:10827398
- 上传时间:2023-02-23
- 格式:DOCX
- 页数:69
- 大小:35.52KB
福建专升本数据结构讲解.docx
《福建专升本数据结构讲解.docx》由会员分享,可在线阅读,更多相关《福建专升本数据结构讲解.docx(69页珍藏版)》请在冰豆网上搜索。
福建专升本数据结构讲解
一、会:
基本概念,基本思想
二、懂:
思想证明
三、写:
C代码
第一章引论
一、算法:
若干指令组成的有限序列。
五个特征:
输入、输出、确定性、有限性、可行性。
二、数据结构=逻辑结构,物理结构
数据逻辑结构(顶层):
三种,线性、层次(树)、图,
逻辑结构是:
成分数据+成分数据之间关系
数据元素(成分数据):
一个同学档案
数据项:
姓名、生日、学号....
数据物理结构(底层,存储结构):
两种,顺序(数组)、非顺序(链表)
同一个逻辑结构可以在不同的物理结构中实现,
但是各种操作算法的具体实现代码不同
(比如在数组插入,在链表中插入算法不同)
涉及题目:
05年二(1,3)
三、复杂度=占用资源的多少,时间、空间
O(...),表示数量级
O
(1) 1、时间复杂度 相对时间,一条指令(语句)运行时间 为1计算: 非递归=主要循环(最费时)执行的次数 递归= 结果中的常数(0)和系数 (1),低阶全 部去掉(0) 3n+7+0.5*n*n=O(n*n) 复杂度类型: 最好、最坏、平均 2、空间复杂度: 辅助数据空间,如果没 有,则是O (1) 涉及题目: 08年2,3,9,12 07年15 四、结构类型、变量、指针 (抽象数据类型不会考): 1、什么是类型? 类型是模板,用于定义变量 intdoublefloatchar... 如果不定义变量,类型没用 intx;x占2字节 doubley;y占8字节 说法: int占2字节,double占8字节 实际上x,y占字节 生活模板C语言 ======================= 二居室模板图纸规划类型intdouble 主卧20平方 小卧10平方 客厅20平方 厨房10 厕所4 阳台4 总计68平方 ---------------------- 房子盖好intx; 张三家是二居室x是整型变量 ==================== 类型: 名字,大小,不占内存 变量: 名字,大小,占内存 ================== C语言允许程序员自己定义类型? 因为C语言原来的类型太少! 比如要存储处理学生档案数据 学号: 整数 姓名: 字符串8个字符 性别: 字符,M,F 地址: 字符串40个字符 分数: 浮点数组[30] -------------- 定义结构类型 intnum; charname[8]; charsex; charaddr[40]; floatscore; typedefstructstudent{ intnum;2成员 charname[8];8 charsex;1 charaddr[40];40 floatscore;4 }STUDENT; 定义一个结构类型! 名字sturctstudent或者STUDENT,大小55字节 ------------- 定义结构变量 structstudentstudent1,student2,stu[100],*p; 或者 STUDENTstudent1,student2,stu[100],*p; p自己占4个字节,管65字节 p里只存一个地址,; intx,y; x=8; 注意: 类型名不能用作变量名 以下代码大错! ! scanf("%d,%s,%c,%s,%f",&student1); printf("%d,%s,%c,%s,%f",student1); ---------------------------------- 引用结构体变量中成员的方式为 结构体变量名.成员名 student1.num=101; student1.name[0]='T'; student1.name[1]='o'; student1.name[2]='m'; student1.name[3]='\0'; student1.sex='M'; student1.score=80.5; 张三家.厨房 李四家.厨房 student2.score=student1.score; sum=student1.score+student2.score; student1.age++; ++student2.age; scanf("%d,%s,%c,%s,%f", &student1.num, &student1.name, &student1.sex, &student1.addr, &student1.score); printf("%d,%s,%c,%s,%f", student1.num, student1.name, student1.sex, student1.addr, student1.score); stu[0].num=103; 数组名[下标].成员名 三个问题: 结构类型定义, 结构变量定义, 结构变量引用 ======================== 简单写法1: 结构类型定义和结构变量定义写在一起, structstudent {intnum; charname[20]; charsex; intage; floatscore; charaddr[30]; }student1,student2; 简单写法2: 结构类型定义和结构变量定义写在一起, 省略类型名字 struct {intnum; charname[20]; charsex; intage; floatscore; charaddr[30]; }student1,student2; 保留字: 不能用作变量名,数组名,函数名 ========================= 指向结构体类型数据的指针 structstudent*p; 或者 STUDENT*p; p自己占4个字节,管65字节 p里只存一个地址,; p=&student1; 把student1的第一个字节的地址存到p中。 能不能通过p来访问student1的成员? 可以。 方式1: p->num就是student1.num p->name就是student1.name p->name[0]就是student1.name[0] p->name[1]就是student1.name[1] p->birthday.month就是student1.birthday.month .... 方式2: 不常用 (*p).num就是student1.num (*p).name就是student1.name p++加65 *(p+2).num等价(p+2)->num (p++)->num*(p++).num (++p)->num ==================== 类型定义: typedef例子: typedefstructx*YYY;//*表示指针变量类型,类型名是YYY,x表示YYY是指向x模板的类型 typedefstructx{ inta; intb; charc; }ListItem; voidmain(){ ListItemy; y.a=6;//y家a房间住6 YYYp; p=&y;//y家地址保存在p中 p->a=7; } 五、指针 6、typedefstructx*YYY;//*表示指针变量类型,类型名是YYY,x表示YYY是指向x模板的类型 typedefstructx{ inta; intb; charc; }ListItem; voidmain(){ ListItemy; //y是结构变量, //y是a,b,c变量的总名字, y.a=6;//一旦有了y,则a,b,c不能 //单独被访问, y.b=7;//必须在y.之后被访问 y.c='a'; //一旦分了房子,不能单独说 //厨房漏水,要说张三家厨房漏水 YYYp; //p是另外一个变量,而且 //是另外一个类型 p=&y; //p与y不是一个变量,也不 //是一个类型,p中存放y首字节地址。 //p管理y的所有字节 p->a=7; //可以通过p来访问y的a,b,c p->b=6; //因为p是指向y类型的指 //针,p->b会自动跳过a所 //占的字节(不止一个字节), //取得b所占的字节(不止一个), //这就是指针类型的必要性。 p->c='b'; } p++相当于p加上sizeof(y), 即y变量占用的字节数 第二章线性表 线性表概念: p18 同一类型元素的有限序列,a1,a2,...an 前驱,后继,长度,空表 一、顺序表(线性表存在数组中) 假定数组是inta[n]; 1、顺序表查询: 给定一个关键字,在数组中顺序比较 for(i=0;i if(key==a[i])break; 查询最好复杂度: O (1),第一个a[0]就是 查询最坏复杂度: O(n),最后一个a[n-1]才是 查询每个元素需要比较次数之和 查询平均复杂度=------------------------------ 元素个数 1+2+3+...+n =--------------------------- n n*(n+1) --------- 2n+1 =-------------=-----=0.5n+0.5=O(n) n2 查询平均复杂度 =(每个元素查询次数*该元素查询概率) 之和 =第1个元素的查询次数*该元素查询概率 +第2个元素的查询次数*该元素查询概率 +...+ +第n个元素的查询次数*该元素查询概率 111 =1*---+2*----+...+n*----=O(n) nnn 假设每个元素的查询概率相同,1/n 2、顺序表插入元素: 插入元素key到a[i] for(j=n-1;j>=i;j--)a[j+1]=a[j];//从后向前移动元素 a[i]=key; 插入最好复杂度: O (1),插在最后元素a[n-1]之后 插入最坏复杂度: O(n),插在第一个元素a[0]之前 插入每个元素移动次数之和 插入平均复杂度=------------------------- 元素个数 0+1+2+3+...+n =--------------------------- n+1 n*(n+1)/2n =-------------=-----=0.5n=O(n) n+12 =(每个位置被插入的移动次数* 该位置被插入的概率)之和 =第1个位置被插入的移动次数*该位置插入概率 +第2个位置被插入的移动次数*该位置插入概率 +...+ +第n+1个位置被插入的移动次数*该位置插入概率 111 =n*------+(n-1)*----+...+0*----=O(n) n+1n+1n+1 假设每个位置被插入的概率相同,1/(n+1) 插入在位置k之后 k=0,1,2,...,n k=0,插入在位置1table[0] k=1,插入在位置2table[1] k=2,插入在位置3table[2] ... k=n,插入在位置n+1table[n] 因此table[k]=x是正确的 3、顺序表删除元素: 删除元素a[i] for(j=i;j 删除最好复杂度: O (1),删除最后一个a[n-1] 删除最坏复杂度: O(n),删除第一个a[0] 删除每个元素移动次数之和 删除平均复杂度=-------------------------=O(n) 元素个数 0+1+...+(n-1)n*(n-1)/2n-1 =----------------=---------------=-------=O(n) nn2 注意: 平均! =最坏 涉及题目: 08年13 07年4,11,22,28 06年一(5) 05年一 (2),二(7),四 (2) 二、链表 1、链表类型: 单链表,循环单链表 双链表,循环双链表 头指针: 一定要有 不是循环链表,一定要有头指针 是循环链表,头指针/尾指针: 要有一个。 头结点: 可有(简单)可无(麻烦), 是否有头结点影响到算法的具体实现 2、类型定义代码 typedefstructnode*link;//指针类型定义 typedefstructnode{//链表实现 ListItemelement; linknext; }Node;//链表结点类型定义 ┏━━━━┳━━━━┓ ┃element┃next┃ ┗━━━━┻━━━━┛ linkfirst;//头指针 first ┏━━┓ ┗━━┛ ↓ ┏━┳┓┏━┳┓┏━┳┓┏━┳━┓ ┃┃┃→┃┃┃→┃┃┃...→┃┃^┃ ┗━┻┛┗━┻┛┗━┻┛┗━┻━┛ 3、创建链表,略去 malloc(n): 在内存中分配一片连续空间,长度是n个字节 将首字节地址返回。 4、遍历链表 intListLength(linkL){ intlen=0; linkp; p=L; while(p! =NULL){ len++; p=p->next; } returnlen; } 调用 length=ListLength(first); 遍历程序写法: linkp; p=first; while(p! =NULL){ p=p->next; } 5、链表插入p26, 假定将新节点x插入到节点i之后。 5.1、最简单情况: 节点i用指向它的指针p来表示。 新节点x用指向它的指针q来表示。 指针调整代码是: q->next=p->next; p->next=q; 插入前 p ┏━━┓ ┗━━┛ ↓ ┏━┳┓┏━┳┓ ┃i┃┃→┃┃┃→... ┗━┻┛┗━┻┛ ┏━┳┓ ┃x┃┃ ┗━┻┛ ↑ ┏━━┓ q┗━━┛ 插入后 p ┏━━┓ ┗━━┛ ↓ ┏━┳┓┏━┳┓ ┃i┃┃-╳→┃┃┃→... ┗━┻┛┗━┻┛ ↓↗ ┏━┳┓╱ ┃x┃┃ ┗━┻┛ ↑ ┏━━┓ q┗━━┛ 5.2、如果节点i需要通过扫描得到, 假定位置是第i个节点(从1开始) 需要链表遍历 intk; linkp; p=first; k=1; while(p! =0&&k p=p->next; i++; } 5.3如果需要建立存储待插入元素x的新结点 linkq; q=(link)malloc(sizeof(Node)); q->element=x; 5.4插入在链表最开头。 q->next=first; first=q; 5.5空表插入。 (创建链表) if(first==NULL){ first=q; q->next=NULL; } 6、节点删除 将节点i删除,p是指向i节点指针变量 6.1、最简单情况: q是指向i的前驱节点指针变量 指针调整代码是: q->next=p->next; free(p); 或者 q->next=q->next->next 删除前 q ┏━━┓ ┗━━┛ ↓ ┏━┳┓┏━┳┓┏━━┳┓ ┃┃┃→┃i┃┃→┃i+1┃┃→... ┗━┻┛┗━┻┛┗━━┻┛ ↑ ┏━━┓ p┗━━┛ 删除后 q ┏━━┓ ┗━━┛ ↓┌→——————→┐ ┏━┳┓┏━┳┓┏━━┳┓ ┃┃┃┃i┃┃→┃i+1┃┃→... ┗━┻┛┗━┻┛┗━━┻┛ ↑(回收) ┏━━┓ p┗━━┛ 6.2、i是链表最开头的节点。 first=first->next; 6.3、如果节点i需要通过扫描得到, 假定位置是第i个节点(从1开始) 找到指向第i-1个结点的指针q q=first; for(k=1;k =NULL;i++) q=q->next; 涉及题目: 08年6,25 07年5,19,20 06年一(1,6),二(18,19) 05年一(1,12), 第三章堆栈Stack 堆栈是特殊的线性表,只能在堆栈顶插入删除元素。 一、用链表实现,进出栈时插入删除结点, 不存在取之不尽的问题,注意尽量 地减少进出栈的时间复杂度,栈顶设在 链表开头。 二、用数组data实现,长度为n, 存在取之不尽的问题 因此设置栈顶指针。 栈顶指针top: int,存储栈顶元素的下标 指向非空位置,除非栈为空。 如果空栈,top=-1 如果满栈,top=n-1 进栈: 将元素x进栈 如果栈满,无法进栈 否则: data[++top]=x 先调整top, 然后放置元素x 出栈: 将栈顶出栈,放置在x中 如果栈空,无法出栈 否则: x=data[top--] 先取走元素,存入x 再调整top data数组 ┏━━━┓ ┃┃n-1 ┣━━━┫ ┃...┃ ┣━━━┫ ┃┃1 ┣━━━┫ ┃┃0 ┗━━━┛ -1top=-1 涉及题目: 08年1 07年2,3 06年一(9) 05年一(4),三(4) 第四章队列Queue 队列是特殊的线性表,只能在队尾插入元素,在队头删除元素。 一、用链表实现,进出队时插入删除结点, 注意尽量减少进出队的时间复杂度O (1), 设置两个指针,队头指针和队尾指针, 二、用数组实现,长度为n,循环队列 (充分利用数组空间) 循环队列方案1 1、maxsize=n,数组长度是n 2、队头指针front(整型,存数组下标), 指向空位置,无论队是否为空 3、队尾指针rear(整型,存数组下标), 指向非空位置,除非队空 4、队空: rear==front, 初始化front=rear=0,0个元素。 5、队满: (rear+1)%n==front, 牺牲一个单元,队满只储存n-1个元素 (为了区分队空和队满) 6、进队: 队是否满? 满则不进,否则 rear=(rear+1)%n, 放新元素在rear位置 (先调整指针,后处理元素) 7、出队: 队是否空? 空则不出,否则 front=(front+1)%n, 取front位置元素 (先调整指针,后处理元素) f 012345n=6 cdeab r 循环队列方案2: 带'的与方案1相反 1、maxsize=n,数组长度是n 2'、队头整型指针front, 指向非空位置,除非队空 3'、队尾整型指针rear, 指向空位置 4、队空: rear==front,初始化f=r=0 5、队满: (rear+1)%n==front, 牺牲一个单元 6'、进队: 放新元素在rear位置 rear=(rear+1)%n, 7'、出队: 取front位置元素 front=(front+1)%n, f 012345n=6 A r 涉及题目: 08年7,16 06年一(10,20) 05年一(3,5),二 (2) 第五章递归 写递归程序: 有时很容易(数学公式存在)。 有时很难(没有现成数学公式) 运行原理: 堆栈,编程时看不见。 递归程序一定可以写成非递归。 对应的非 递归一般使用堆栈。 递归变成非递归有时候很难, 对问题的理解不够。 比如Ackerman函数,写成递归很容易, 变成非递归很难。 递归算法复杂度分析有时候很难 (生成函数)。 同样一个问题有时候用递归很容易 解决,用非递归不容易解决 同样一个问题有时候用非递归很容 易解决,用递归不容易解决 同样一个问题有时候用非递归,用 递归都不容易解决 =========================================== 如果没有数学公式,简单递归程序写法 1、写出递归函数的定义: 函数名,参数,结果(返回值类型和意义) 2、处理边界情况 3、按照递归函数的定义 (利用低一级结果,得到本级的结果), 自己调用自己,自圆其说 ========================================= 写非递归写递归 |-1(无定义),n<0 n! =n*...*2*1=|-1,0<=n<=1 |-n*(n-1)! n>1 //非递归: O(n) intf(intn){//f(n)计算n! inti,j; if(n<=1)return1; j=1; for(i=1;i<=n;i++) j=j*i; returnj; } //递归 intF(intn){ //写出函数定义: F(n)算出n! if(n<=1)return1;//处理边界情况 returnn*F(n-1);//自己调用自己, }//同时满足结果 voidmain(){ intx,y; x=F(5); y=f(5); printf("%d%d",x,y); } 设F(n)的时间复杂度是T(n) 则F(n-1)的时间复杂度是T(n-1) T (1)=1 T(n)=1+T(n-1) T(n-1)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 福建 数据结构 讲解