数据结构C语言版期末复习.docx
- 文档编号:25262867
- 上传时间:2023-06-06
- 格式:DOCX
- 页数:23
- 大小:326.46KB
数据结构C语言版期末复习.docx
《数据结构C语言版期末复习.docx》由会员分享,可在线阅读,更多相关《数据结构C语言版期末复习.docx(23页珍藏版)》请在冰豆网上搜索。
数据结构C语言版期末复习
数据结构(C语言版)期末复习汇总
第一章绪论
数据结构:
是一门研究非数值计算程序设计中的操作对象,以及这些对象之间的关系和操作的学科。
数据结构分为:
逻辑结构、物理结构、操作三部分
逻辑结构:
集合、线性结构、树形结构、图(网)状结构
物理结构(存储结构):
顺序存储结构、链式存储结构
算法:
是为了解决某类问题而规定的一个有限长的操作序列。
算法五个特性:
有穷性、确定性、可行性、输入、输出
评价算法优劣的基本标准(4个):
正确性、可读性、健壮性、高效性及低存储量
语句频度的计算。
算法的时间复杂度:
常见有:
O
(1),O(n),O(n2),O(log2n),O(nlog2n),O(2n)
第二章线性表
线性表的定义和特点:
线性表:
由n(n≥0)个数据特性相同的元素构成的有限序列。
线性表中元素个数n(n≥0)定义为线性表的长度,n=0时称为空表。
非空线性表或线性结构,其特点:
(1)存在唯一的一个被称作“第一个”的数据元素;
(2)存在唯一的一个被称作“最有一个”的数据元素;
(3)除第一个之外,结构中的每个数据元素均只有一个前驱;
(4)除最后一个之外,结构中的每个数据元素均只有一个后继。
顺序表的插入:
共计n个元素,在第i位插入,应移动(n-i+1)位元素。
顺序表的删除:
共计n个元素,删除第i位,应移动(n-i)位元素。
线性表的两种存储方式:
顺序存储、链式存储。
顺序存储
概念:
以一组连续的存储空间存放线性表;
优点:
逻辑相邻,物理相邻;可随机存取任一元素;存储空间使用紧凑;
缺点:
插入、删除操作需要移动大量的元素;预先分配空间需按最大空间分配,利用不充分;
表容量难以扩充;
操作:
查找、插入、删除等
查找:
ListSearch(SqlListL,ElemTypex,intn)
{
inti;
for(i=0;i {if(x==L.elem[i])break;} if(i==n)return(0); else return(i+1); }//ListSearch 删除: ListDelete(SqlList&L,inti,ElemType&e) { if(i<1||i>L.length) returnERROR;//i值不合法 p=&(L.elem[i-1]);//p为被删除元素的位置 e=*p;//被删除元素的值赋给e q=L.elem+L.length-1//表尾元素的位置 for(++p;p<=q;++p) *(p-1)=*p;//被删除元素之后的元素左移 --L.length;//表长减1 returne; }//ListDelete 插入: ListInsert(SqlList&L,inti,ElemTypee) {if(i<1||i>L.length+1) returnERROR;//i值不合法。 if(L.length>=Listsize)//当前存储空间已满,增加分配 {newbase=(ElemType*)realloc(L.elem,(L.Listsize+LISTINCREMENT)*sizeof(ElemType)); //realloc(void*p,unsignedsize)该函数将p所指出的已分配内存区的大小改为size,size可以比原来分配的空间大或小// If(! newbase)exit(OVERFLOW);//存储分配失败 L.elem=newbase;//新基址 L.Listsize+=LISTINCREMENT;);//增加存储容量 } q=&(L.elem[i-1]);//q为插入位置 for(p=&L.elem[L.length-1];p>=q;--p)*(p+1)=*p;//插入位置之后的元素右移 *q=e;//插入e ++L.length;//表长增加1 returnOK; }//ListInsert 单链表——线性表的链式存储结构之一 概念: 线性链表又称单链表,结点: 数据域,指针域;头指针,头结点。 单链表特点: 用指针表示数据之间的逻辑关系(逻辑相邻的元素物理位置不一定相邻)。 它是一种动态结构,不需预先分配空间; 不足: 指针占用额外存储空间;不能随机存取,查找速度慢。 节点定义: “数据+指针” typedefstructLNode{ DataTypedata; structLNode*next; }LNode,*LinkList; 单链表的插入: 元素x结点应预先生成: S=(test*)malloc(m); S->data=x; S->next=p->next p->next=s 单链表删除: q=p->next;//保存b的指针,靠它才能指向c p->next=q->next;//a、c两结点相连 free(q);//删除b结点,彻底释放 线性表的应用: (1): 用单链表结构存放26个英文字母组成的线性表(a,b,c,…,z),请写出C语言程序。 #include #include /*将全局变量及函数提前说明: */ typedefstructliu{ chardata; structliu*next; }test; test*p,*q,*head;//一般需要3个指针变量 intn;//数据元素的个数 intm=sizeof(test);/*结构类型定义好之后,每个变量的长度就固定了,m求一次即可*/ voidbuild()//字母链表的生成。 要一个一个链入 { inti; p=(test*)malloc(m);//m=sizeof(test)前面已求出 head=p;//头指针,没有头结点 for(i=1;i<26;i++)//因尾结点要特殊处理,故i≠26 { p->data=i+‘a’-1;//第一个结点值为字符a p->next=(test*)malloc(m);//为后继结点开新空间! p=p->next;//让指针变量P改为指向后继结点 } p->data=i+‘a’-1;//最后一个元素要单独处理 p->next=NULL;//单链表尾结点的指针域要置空! } voiddisplay()/*字母链表的输出*/ {p=head; while(p)/*只要没到最后一个元素,就不停地“顺藤摸瓜”输出*/ {printf("%c",p->data); p=p->next; } } (2)线性表的合并: (顺序储存结构) 算法2.1: LA=(7,5,3,11)LB=(2,6,3) 合并后LA=(7,5,3,11,2,6) 算法思想: 扩大线性表LA,将存在于线性表LB中而不存在于线性表LA中的数据元素插入到线性表LA中去。 只要从线性表LB中依次取得每个数据元素,并依值在线性表LA中进行查访,若不存在,则插入之。 voidunion(List&LA,List&LB)//主函数,参数为两个线性表 { La_len=ListLength(LA);//求得线性表LA的长度 while(! ListEmpty(LB))//依次处理LB中元素直至LB为空表止 { ListDelete(LB,1,e);//从LB中删除第1个数据元素并赋给e if(! LocateElem(LA,e,equal()) ListInsert(LA,++La_len,e); //当LA中不存在和e值相同的数据元素时进行插入 }// DestroyList(LB); //销毁线性表LB }//union 第三章栈和队列 栈的类型定义: 栈(Stack)是限制在表的一端进行插入和删除运算的线性表,通常称插入、删除的这一端为栈顶(Top),另一端为栈底(Bottom)。 当表中没有元素时称为空栈。 假设栈S=(a1,a2,a3,…an),则a1称为栈底元素,an为栈顶元素。 栈中元素按a1,a2,a3,…an的次序进栈,退栈的第一个元素应为栈顶元素。 即,栈的修改是按后进先出的原则进行的。 因此,栈称为后进先出表(LIFO)。 栈的进栈(push)操作: StatusPush(Stack&S,SElemTypee){ //插入元素e为新的栈顶元素 if(S.top-S.bottom>=S.stacksize){//栈满,追加存储空间 S.bottom=(SElemType)realloc(S.bottom,(S.stacksize+STACKINCREMENT)*sizeof(ElemType)); if(! S.bottom)exit(overflow);//存储分配失败 S.top=S.bottom+S.stacksize;//设置新栈的栈顶 S.stacksize+=STACKINCREMENT;}//设置新栈的大小 *S.top++=e;//先赋值,后加1 ReturnOK; }//Push 出栈(pop)操作: StatusPop(Stack&S,SElemType&e){ //若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR if(S.top==S.bottom)ReturnERROR; S.top--;e=*S.top; ReturnOK; }//Pop 进栈、出栈顺序: 对于一个栈,给出输入项A、B、C,如果输入项序列由ABC组成,试给出所有可能的输出序列。 A进A出B进B出C进C出ABC A进A出B进C进C出B出ACB A进B进B出A出C进C出BAC A进B进B出C进C出A出BCA A进B进C进C出B出A出CBA 不可能产生输出序列CAB 栈的应用: 数值转换 算法思想: 首先将按照上述计算过程中得到的八进制数的各位依次进栈,然后将栈中的八进制数依次出栈输出,输出结果就是该是十进制数转换得到的八进制数。 N=(Ndivd)×d+Nmodd(其中: div为整除运算,mod为求余运算) 例如(1348)10=(2504)8,其运算过程如下: NNdiv8Nmod8 13481684 168210 2125 202 算法: voidconversion(intn,intd)/*将十进制整数N转换为d(2或8)进制数*/ {SqStackS;intk,*e;//建立堆栈S S=Init_Stack();//堆栈S初始化 while(n>0){k=n%d;push(S,k);n=n/d;} /*求出所有的余数,进栈*/ while(S.top! =0)/*栈不空时出栈,输出*/ {pop(S,e); printf(“%1d”,*e); } } 队列的类型定义: 定义: 队列是限定只能在表的一端进行插入,在表的另一端进行删除的线性表 队尾(rear): 允许插入的一端 队头(front): 允许删除的一端 队列特点: 先进先出(FIFO) 队列储存结构: 顺序队、链队 顺序队列操作: 插入: insertseq(Sequeue*q,Elemtypex) {/*将元素x插入到队列q中,作为q的新队尾,即入队操作*/ if(q->rear>Maxsize-1)returnFALSE;/*队列满*/ else { q->data[q->rear]=x;//先插入数据 q->rear++;//再移动指针 returnTRUE; } }//insertseq 删除: Elemtypedeleteseq(Sequeue*q) {/*若队列q不为空,则删除队头元素,即出队列操作*/ Elemtypex;//定义数据元素变量,存放删除元素 if(q->rear==q->front)returnNULL;//队列空 else {x=q->data[q->front];//先删除数据 q->front++;//再移动指针 returnx; } }//deleteseq 循环顺序队插入、删除分析: 第四章串 串的类型定义: 串是字符串的简称。 它是一种在数据元素的组成上具有一定约束条件的线性表,即要求组成线性表的所有数据元素都是字符,所以,人们经常又这样定义串: 串是一个有穷字符序列。 串一般记作: s=“a1a2...an”(n≥0) 其中,s是串的名称,用双引号“”括起来的字符序列是串的值;ai可以是字母、数字或其他字符;串中字符的数目n被称作串的长度。 当n=0时,串中没有任何字符,其串的长度为0,通常被称为空串,由空格组成的字符串叫空白串。 子串、主串: 串中任意连续的字符组成的子序列被称为该串的子串。 包含子串的串又被称为该子串的主串。 串操作: StrAssign(&T,chars)//串赋值,生成值为chars的串T StrCompare(S,T)//串比较,若S>T,返回值大于0… StrLength(S)//求串长,即返回S的元素个数 Concat(&T,S1,S2)//串连接,用T返回S1+S2的新串 SubString(&Sub,S,pos,len)//求S中pos起长度为len的子串 Index(S,T,pos)//返回子串T在pos之后的位置 Replace(&S,T,V)//用子串V替换子串T 第五章树和二叉树 树的定义: 树(tree)是n(n≥0)个结点的有限集T,其中: 有且仅有一个特定的结点,称为树的根(root); 当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,……Tm,其中每一个集合本身又是一棵树,称为根的子树(subtree)。 特点: 树中至少有一个结点: 根 树中各子树是互不相交的集合 线性结构与树形结构的区别 线性结构 树形结构 第一个数据元素(无前驱) 根结点(无前驱) 最后一个数据元素(无后继) 多个叶子结点(无后继) 其它数据元素(一个前驱,一个后继) 其它数据元素(一个前驱、多个后继) 树的基本术语: 结点(node): 表示树中的元素,包括数据元素及若干指向其子树的分支 结点的度(degree): 结点拥有的子树数 树的度: 一棵树中最大的结点度数 叶子(leaf): 度为0的结点(终端结点) 孩子(child): 结点子树的根称为该结点的~~ 双亲(parents): 孩子结点的上层结点叫该结点的~~ 兄弟(sibling): 同一双亲的孩子 子孙: 以某结点为根的子树中的所有结点都被称为是该结点的~~ 祖先: 从根结点到该结点路径上的所有结点 堂兄弟: 双亲在同一层的结点互为~~ 结点的层次(level): 从根结点算起,根为第一层,它的孩子为第二层…… 深度(depth): 树中结点的最大层次数 森林(forest): m(m0)棵互不相交的树的集合 有序树、无序树: 如果树中每棵子树从左向右的排列拥有一定的顺序,不得互换,则称为有序树,否则称为无序树 二叉树的定义: 二叉树是n(n≥0)个结点的有限集,它或为空树(n=0),或由一个根结点和两棵分别称为左子树和右子树的互不相交的二叉树构成。 特点 每个结点至多有二棵子树(即不存在度大于2的结点); 二叉树的子树有左、右之分,且其次序不能任意颠倒。 二叉树的性质: 性质1: 在二叉树的第i层上最多有2i-1个结点(i≥1); 性质2: 深度为K的二叉树最多有2K-1个结点(K≥1); 性质3: 对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1; 完全二叉树 定义: 一棵深度为h,具有n个结点的二叉树,若将它与一棵同深度的满二叉树中的所有结点按从上到下,从左到右的顺序分别进行编号,且该二叉树中的每个结点分别与满二叉树中编号为1~n的结点位置一一对应,则称这棵二叉树为完全二叉树。 特点: 叶子结点只可能在层次最大的两层上出现; 对任一结点,若其右分支下子孙的最大层次为L,则其左分支下子孙的最大层次必为L或L+1。 性质4: 具有n个结点的完全二叉树的深度为log2n+1。 (其中,log2n的结果是不大于log2n的最大整数。 ) 性质5: 对于有n个结点的完全二叉树中的所有结点按从上到下,从左到右的顺序进行编号,则对任意一个结点i(1≤i≤n),都有: (1)如果i=1,则结点i是这棵完全二叉树的根,没有双亲。 否则其双亲结点的编号为i/2; (2)如果2i>n,则结点i没有左孩子。 否则其左孩子结点的编号为2i; (3)如果2i+1>n,则结点i没有右孩子。 否则其右孩子结点的编号为2i+1。 二叉树遍历: 先序遍历: 先访问根结点,然后分别先序遍历左子树、右子树【包络法】 中序遍历: 先中序遍历左子树,然后访问根结点,最后中序遍历右子树【垂直映射法】 后序遍历: 先后序遍历左、右子树,然后访问根结点 例: 先序遍历: abdeghcf 中序遍历: dbgheafc 后序遍历: dhgebfca 层次遍历: abcdefgh 根据遍历结果恢复二叉树的条件(先序加中序或者中序加后序) 输出二叉树的节点 DLR(x*root) {if(root! =NULL)//非空二叉树 {printf(“%d”,root->data);//访问D,printf可以为其他函数 DLR(root->lchild);//递归遍历左子树 DLR(root->rchild);//递归遍历右子树 } return(0); } 输出二叉树的叶子节点: DLR(x*root)/*先序遍历输出叶子结点*/ {if(root! =NULL)/*root为指向二叉树根结点的指针*/ {if(root->lchild==NULL&&root->rchild==NULL) printf(“%d”,root->data);/*输出叶子结点*/ DLR(root->lchild);/*先序遍历左子树*/ DLR(root->rchild);/*先序遍历右子树*/ } } 统计二叉树叶子节点数: DLR(x*root)//采用先序遍历的递归算法 {if(root! =NULL)//非空二叉树条件,还可写成if(root) {if(! root->lchild&&! root->rchild)//是叶子结点则统计并打印 sum++;//统计叶子节点数 DLR(root->lchild);//递归遍历左子树,直到叶子处; DLR(root->rchild);}//递归遍历右子树,直到叶子处; }return(0);} 霍夫曼树、霍夫曼编码: 例: W={5,29,7,8,14,23,3,11} 第六章图 图的定义: 图(Graph): 图G是由两个集合V(G)和VR(G)组成的,记为: G=(V,VR) 其中: V(G)是顶点的非空有限集;VR(G)是边的有限集合,边是顶点的无序对或有序对。 有向图,无向图 顶点的度: 无向图中,顶点的度为与每个顶点相连的边数; 有向图中,顶点的度分成入度与出度 入度: 以该顶点为头的弧的数目 出度: 以该顶点为尾的弧的数目 路径: 路径是顶点的序列V={Vi0,Vi1,……Vin},满足(Vij-1,Vij)E或 路径长度: 沿路径边的数目或沿路径各边权值之和 回路: 第一个顶点和最后一个顶点相同的路径叫~ 简单路径: 序列中顶点不重复出现的路径叫~ 简单回路: 除了第一个顶点和最后一个顶点外,其余顶点不重复出现的回路叫~ 连通: 从顶点V到顶点W有一条路径,则说V和W是连通的 连通图: 图中任意两个顶点都是连通的叫~ 连通分量: 非连通图的每一个连通部分叫~ 强连通图: 有向图中,如果对每一对Vi,VjV,ViVj,从Vi到Vj和从Vj到Vi都存在路径,则称G是~ 邻接矩阵、邻接表: 图的深度遍历: 方法: 从图的某一顶点V0出发,访问此顶点;然后依次从V0的未被访问的邻接点出发,深度优先遍历图,直至图中所有和V0相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作起点,重复上述过程,直至图中所有顶点都被访问为止。 必须说明,若不给定存储结构,深度优先遍历的结果不唯一。 因为哪个顶点是第一邻接点未确定。 给定存储结构后,深度优先遍历的结果是唯一的。 图的广度遍历: 方法: 从图的某一顶点V0出发,访问此顶点后,依次访问V0的各个未曾访问过的邻接点;然后分别从这些邻接点出发,广度优先遍历图,直至图中所有已被访问的顶点的邻接点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作起点,重复上述过程,直至图中所有顶点都被访问为止。 广度遍历: V1V2V3V4V5V6V7V8 最小生成树: 同一个连通网的最小生成树可能是不唯一的,但其代价都是最小(唯一的)。 克鲁斯卡尔算法: 普里姆算法: AOV网,拓扑排序 有向无环图(DAG),AOV网;拓扑排序。 拓扑排序,一句话“每次删除入度为0的顶点并将其输出”。 注意: 拓扑排序的结果不一定是唯一的。 如: ACBDE也是以上DAG图的拓扑有序序列。 AOE网,关键路径 AOE 网(活动在边上),边代表活动或任务,顶点代表事件。 事件i发生后,其后继活动a(i,*)都可以开始;只有所有先导活动a(*,j)都结束后,事件j才发生。 关键路径算法 问题: a)整个工程完工需要多长时间? b)哪些活动影响工程的进度? 求关键路径。 事件(顶点)i: 最早发生时间ve(i),最晚发生时间vl(i); 活动(边)a(i,j): 最早开始时间e(i,j),最晚开始时间l(i,j)。 于是,整个工程完工的时间就是终点的最早发生时间;关键路径就是路径长度最长的路径。 例: 某工程的AOE网如下,求1)整个工程完工需要多长时间,2)关键路径。 分析: 按照拓扑有序排列顶点,然后“从前往后”计算事件的最早发生时间得到总时间,再“从后往前”计算事件的最晚发生时间,最后计算活动的最早和最晚开始时间得到关键活动和关键路径。 表7.2关键路径
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 语言版 期末 复习