数据结构综合.docx
- 文档编号:6001694
- 上传时间:2023-01-02
- 格式:DOCX
- 页数:20
- 大小:77.18KB
数据结构综合.docx
《数据结构综合.docx》由会员分享,可在线阅读,更多相关《数据结构综合.docx(20页珍藏版)》请在冰豆网上搜索。
数据结构综合
第1章绪论
1.数据的逻辑结构分哪几种,为什么说逻辑结构是数据组织的主要方面?
2.数据的存储结构由哪四种基本的存储方法实现?
3.设n是正整数,求下列程序段中带@记号的语句的执行次数。
(1)i=1;k=0;
while(i {k=k+50*i;i++; @ } (2)x=y=0; for(i=0;i for(j=0;j {x++; @ for(k=0;k y++; @ } (3)x=91;y=100; while(y>0) if(x>100) {x=x-10;y--; @ } elsex++; @ 4.已知输入x,y,z三个不相等的整数,设计一个“高效”算法,使得这三个数按从小到大输出。 “高效”的含义是用最少的元素比较次数、元素移动次数和输出次数。 答案: 1.【解答】数据的逻辑结构分为线性结构和非线性结构。 (也可以分为集合、线性结构、树形结构和图形即网状结构)。 逻辑结构是数据组织的某种“本质性”的东西: (1)逻辑结构与数据元素本身的形式、内容无关。 (2)逻辑结构与数据元素的相对位置无关。 (3)逻辑结构与所含数据元素的个数无关。 2.答: 四种表示方法 (1)顺序存储方式。 数据元素顺序存放,每个存储结点只含一个元素。 存储位置反映数据元素间的逻辑关系。 存储密度大,但有些操作(如插入、删除)效率较差。 (2)链式存储方式。 每个存储结点除包含数据元素信息外还包含一组(至少一个)指针。 指针反映数据元素间的逻辑关系。 这种方式不要求存储空间连续,便于动态操作(如插入、删除等),但存储空间开销大(用于指针),另外不能折半查找等。 (3)索引存储方式。 除数据元素存储在一地址连续的内存空间外,尚需建立一个索引表,索引表中索引指示存储结点的存储位置(下标)或存储区间端点(下标),兼有静态和动态特性。 (4)散列存储方式。 通过散列函数和解决冲突的方法,将关键字散列在连续的有限的地址空间内,并将散列函数的值解释成关键字所在元素的存储地址,这种存储方式称为散列存储。 其特点是存取速度快,只能按关键字随机存取,不能顺序存取,也不能折半存取。 3.【解答】 (1)n-1 (2)n+1,n(n+1),n2,(n+1)n2,n3 (3)100,1000 4.【算法】 voidBest() {//按序输出三个整数的优化算法 inta,b,c,t; scanf(“%d%d%d”,&a,&b,&c); if(a>b) {t=a; a=b;b=t: } //a和b已正序 if(b>c) {t=c;c=b; //c已到位 if(a>t){b=a;a=t;} //a和b已正序 elseb=t; } printf(“%d,%d,%d\n”,a,b,c); //最佳2次比较,无移动;最差3次比较,7个赋值 } 第2章线性表 0 1.下面关于线性表的叙述中,错误的是哪一个? () A.线性表采用顺序存储,必须占用一片连续的存储单元。 B.线性表采用顺序存储,便于进行插入和删除操作。 C.线性表采用链接存储,不必占用一片连续的存储单元。 D.线性表采用链接存储,便于插入和删除操作。 2.线性表是具有n个()的有限序列(n>0)。 A.表元素B.字符C.数据元素 D.数据项E.信息项 3.线性表(a1,a2,…,an)以链接方式存储时,访问第i位置元素的时间复杂性为() A.O(i)B.O (1) C.O(n)D.O(i-1) 4.若长度为n的线性表采用顺序存储结构,在其第i个位置插入一个新元素的算法的时间复杂度为()(1<=i<=n+1)。 A.O(0)B.O (1) C.O(n)D.O(n2) 5.对于顺序存储的线性表,访问结点和增加、删除结点的时间复杂度为()。 A.O(n)O(n)B.O(n)O (1)C.O (1)O(n)D.O (1)O (1) 6.对于一个头指针为head的带头结点的单链表,判定该表为空表的条件是() A.head==NULLB.head→next==NULLC.head→next==headD.head! =NULL 7.链表不具有的特点是() A.可随机访问任一元素 B.插入、删除不需要移动元素 C.不必事先估计存储空间 D.所需空间与线性长度成正比 8.在双向链表指针p的结点前插入一个指针q的结点操作是()。 A.p->Llink=q;q->Rlink=p;p->Llink->Rlink=q;q->Llink=q; B.p->Llink=q;p->Llink->Rlink=q;q->Rlink=p;q->Llink=p->Llink; C.q->Llink=p->Llink;q->Rlink=q;p->Llink=q;p->Llink=q; D.q->Rlink=p;q->Llink=p->Llink;p->Llink->Rlink=q;p->Llink=q; 9.在单链表指针为p的结点之后插入指针为s的结点,正确的操作是: ()。 A.s->next=p->next;p->next=s; B.p->next=s;s->next=p->next; C.p->next=s;p->next=s->next; D.p->next=s->next;p->next=s; 10.对于一个头指针为head的带头结点的单链表,判定该表为空表的条件是() A.head==NULLB.head→next==NULLC.head→next==headD.head! =NULL 答案: 1.B2.C3.C4.C5.C 6.B7.A8.D9.A10.B 作业一 1.线性表有两种存储结构: 一是顺序表,二是链表。 试问: (1)如果有n个线性表同时并存,并且在处理过程中各表的长度会动态变化,线性表的总数也会自动地改变。 在此情况下,应选用哪种存储结构? 为什么? (2)若线性表的总数基本稳定,且很少进行插入和删除,但要求以最快的速度存取线性表中的元素,那么应采用哪种存储结构? 为什么? 2.设双向循环链表中结点的数据域、前驱和后继指针域分别为data,pre和next,写出在指针p所指结点之前插入一s结点的C语言描述语句。 3.一线性表存储在带头结点的双向循环链表中,L为头指针。 如下算法: (1)说明该算法的功能。 (2)在空缺处填写相应的语句。 voidunknown(BNODETP*L) {… p=L->next;q=p->next;r=q->next; while(q! =L) {while(p! =L)&&(p->data>q->data)p=p->prior; q->prior->next=r; (1)______; q->next=p->next;q->prior=p; (2)______;(3)______;q=r;p=q->prior; (4)______; } } 4.已知线性表(a1a2a3…an)按顺序存于内存,每个元素都是整数,试设计用最少时间把所有值为负数的元素移到全部正数值元素前边的算法: 例: (x,-x,-x,x,x,-x…x)变为(-x,-x,-x…x,x,x)。 答案: 1. (1)选链式存储结构。 它可动态申请内存空间,不受表长度(即表中元素个数)的影响,插入、删除时间复杂度为O (1)。 (2)选顺序存储结构。 顺序表可以随机存取,时间复杂度为O (1)。 2.在指针p所指结点前插入结点s的语句如下: s->pre=p->pre;s->next=p;p->pre->next=s;p->pre=s; 3. (1)本算法功能是将双向循环链表结点的数据域按值自小到大排序,成为非递减(可能包括数据域值相等的结点)有序双向循环链表。 (2) (1)r->prior=q->prior;∥将q结点摘下,以便插入到适当位置。 (2)p->next->prior=q;∥ (2)(3)将q结点插入 (3)p->next=q; (4)r=r->next;或r=q->next;∥后移指针,再将新结点插入到适当位置。 4.[题目分析]题目要求重排n个元素且以顺序存储结构存储的线性表,使得所有值为负数的元素移到正数元素的前面。 这可采用快速排序的思想来实现,只是提出暂存的第一个元素(枢轴)并不作为以后的比较标准,比较的标准是元素是否为负数。 intRearrange(SeqLista;intn) ∥a是具有n个元素的线性表,以顺序存储结构存储,线性表的元素是整数。 本算法重排线性表a, ∥使所有值为负数的元素移到所有值为正数的数的前面。 {i=0;j=n-1;∥i,j为工作指针(下标),初始指向线性表a的第1个和第n个元素。 t=a[0];∥暂存枢轴元素。 while(i {while(i if(i while(i if(i } a[i]=t;∥将原第一元素放到最终位置。 } [算法讨论]本算法时间复杂度为O(n)。 算法只是按题目要求把正负数分开,如要求统计负数和大于等于零的个数,则最后以t来定。 如t为负数,则0至i共i+1个负数,n-1-i个正数(包括零)。 另外,题目并未提及零的问题,笔者将零放到正数一边。 对此问题的扩充是若元素包含正数、负数和零,并要求按负数、零、正数的顺序重排线性表,统计负数、零、正数的个数。 第3章栈和队列 1.假设以数组A[m]存放循环队列的元素,其头尾指针分别为front和rear,则当前队列中的元素个数为()。 A.(rear-front+m)%mB.rear-front+1C.(front-rear+m)%mD.(rear-front)%m 2.若用一个大小为6的数组来实现循环队列,且当前rear和front的值分别为0和3,当从队列中删除一个元素,再加入两个元素后,rear和front的值分别为多少? () A.1和5B.2和4C.4和2D.5和1 3.栈的特点是(①),队列的特点是(②),栈和队列都是(③)。 若进栈序列为1,2,3,4则(④)不可能是一个出栈序列(不一定全部进栈后再出栈);若进队列的序列为1,2,3,4则(⑤)是一个出队列序列。 ①,②: A.先进先出B.后进先出C.进优于出D.出优于进 ③: A.顺序存储的线性结构B.链式存储的线性结构 C.限制存取点的线性结构D.限制存取点的非线性结构 ④,⑤: A.3,2,1,4B.3,2,4,1C.4,2,3,1D.4,3,2,1F.1,2,3,4G.1,3,2,4 4.算术表达式求值的流程,其中OPTR为算术符栈,OPND为操作数栈,precede(oper1,oper2)是比较运算符优先级别的函数,operate(opnd1,oper,opnd2)为两操作数的运算结果函数。 (#表示运算起始和终止符号) FUNCTIONexp_reduced: operandtype; INITSTACK(OPTR);PUSH(OPTR"#");INITSTACK(OPND);read(w); WHILENOT((w='#’)AND(GETTOP(OPTR)='#'))DO IFNOTwinopTHENPUSH(OPND,w); ELSECASEprecede(GETTOP(OPTR),w)OF '<': [ (1)_______;read(w);] '=': [ (2)_______;read(w);]; '>': [theta: =POP(OPTR);b: =POP(OPND);a: =POP(OPND);(3)_______;] ENDC; RETURN(GETTOP(OPND)); ENDF; 作业 1.如果用一个循环数组q[0..m-1]表示队列时,该队列只有一个队列头指针front,不设队列尾指针rear,而改置计数器count用以记录队列中结点的个数。 (1)编写实现队列的三个基本运算: 判空、入队、出队 (2)队列中能容纳元素的最多个数是多少? 2.设表达式以字符形式已存入数组E[n]中,‘#’为表达式的结束符,试写出判断表达式中括号(‘(’和‘)’)是否配对的C语言描述算法: EXYX(E);(注: 算法中可调用栈操作的基本算法。 ) 3.请利用两个栈S1和S2来模拟一个队列。 已知栈的三个运算定义如下: PUSH(ST,x): 元素x入ST栈;POP(ST,x): ST栈顶元素出栈,赋给变量x;Sempty(ST): 判ST栈是否为空。 那么如何利用栈的运算来实现该队列的三个运算: enqueue: 插入一个元素入队列;dequeue: 删除一个元素出队列;queue_empty: 判队列为空。 (请写明算法的思想及必要的注释) 答案: 1.typedefstruct {elemtpq[m]; intfront,count;//front是队首指针,count是队列中元素个数。 }cqnode;//定义类型标识符。 (1)判空: intEmpty(cqnodecq)//cq是cqnode类型的变量 {if(cq.count==0)return (1);elsereturn(0);//空队列} 入队: intEnQueue(cqnodecq,elemtpx) {if(count==m){printf(“队满\n”);exit(0);} cq.q[(cq.front+count)%m]=x;//x入队 count++;return (1);//队列中元素个数增加1,入队成功。 } 出队: intDelQueue(cqnodecq) {if(count==0){printf(“队空\n”);return(0);} printf(“出队元素”,cq.q[cq.front]); x=cq.q[cq.front]; cq.front=(cq.front+1)%m;//计算新的队头指针。 return(x) } (2)队列中能容纳的元素的个数为m。 队头指针front指向队头元素。 2.[题目分析]判断表达式中括号是否匹配,可通过栈,简单说是左括号时进栈,右括号时退栈。 退栈时,若栈顶元素是左括号,则新读入的右括号与栈顶左括号就可消去。 如此下去,输入表达式结束时,栈为空则正确,否则括号不匹配。 intEXYX(charE[],intn) //E[]是有n字符的字符数组,存放字符串表达式,以‘#’结束。 本算法判断表达式中圆括号是否匹配。 {chars[30];//s是一维数组,容量足够大,用作存放括号的栈。 inttop=0;//top用作栈顶指针。 s[top]=‘#’;//‘#’先入栈,用于和表达式结束符号‘#’匹配。 inti=0;//字符数组E的工作指针。 while(E[i]! =‘#’)//逐字符处理字符表达式的数组。 switch(E[i]) {case‘(’: s[++top]=‘(’;i++;break; case‘)’: if(s[top]==‘(’{top--;i++;break;} else{printf(“括号不配对”);exit(0);} case‘#’: if(s[top]==‘#’){printf(“括号配对\n”);return (1);} else{printf(“括号不配对\n”);return(0);}//括号不配对 default: i++;//读入其它字符,不作处理。 } }//算法结束。 [算法讨论]本题是用栈判断括号匹配的特例: 只检查圆括号的配对。 一般情况是检查花括号(‘{’,‘}’)、方括号(‘[’,‘]’)和圆括号(‘(’,‘)’)的配对问题。 编写算法中如遇左括号(‘{’,‘[’,或‘(’)就压入栈中,如遇右括号(‘}’,‘]’,或‘)’),则与栈顶元素比较,如是与其配对的括号(左花括号,左方括号或左圆括号),则弹出栈顶元素;否则,就结论括号不配对。 在读入表达式结束符‘#’时,栈中若应只剩‘#’,表示括号全部配对成功;否则表示括号不匹配。 另外,由于本题只是检查括号是否匹配,故对从表达式中读入的不是括号的那些字符,一律未作处理。 再有,假设栈容量足够大,因此入栈时未判断溢出。 3.[题目分析]栈的特点是后进先出,队列的特点是先进先出。 所以,用两个栈s1和s2模拟一个队列时,s1作输入栈,逐个元素压栈,以此模拟队列元素的入队。 当需要出队时,将栈s1退栈并逐个压入栈s2中,s1中最先入栈的元素,在s2中处于栈顶。 s2退栈,相当于队列的出队,实现了先进先出。 显然,只有栈s2为空且s1也为空,才算是队列空。 (1)intenqueue(stacks1,elemtpx) //s1是容量为n的栈,栈中元素类型是elemtp。 本算法将x入栈,若入栈成功返回1,否则返回0。 {if(top1==n&&! Sempty(s2))//top1是栈s1的栈顶指针,是全局变量。 {printf(“栈满”);return(0);}//s1满s2非空,这时s1不能再入栈。 if(top1==n&&Sempty(s2))//若s2为空,先将s1退栈,元素再压栈到s2。 {while(! Sempty(s1)){POP(s1,x);PUSH(s2,x);} PUSH(s1,x);return (1);//x入栈,实现了队列元素的入队。 } (2)voiddequeue(stacks2,s1) //s2是输出栈,本算法将s2栈顶元素退栈,实现队列元素的出队。 {if(! Sempty(s2))//栈s2不空,则直接出队。 {POP(s2,x);printf(“出队元素为”,x);} else//处理s2空栈。 if(Sempty(s1)){printf(“队列空”);exit(0);}//若输入栈也为空,则判定队空。 else//先将栈s1倒入s2中,再作出队操作。 {while(! Sempty(s1)){POP(s1,x);PUSH(s2,x);} POP(s2,x);//s2退栈相当队列出队。 printf(“出队元素”,x); } }//结束算法dequue。 (3)intqueue_empty() //本算法判用栈s1和s2模拟的队列是否为空。 {if(Sempty(s1)&&Sempty(s2))return (1);//队列空。 elsereturn(0);//队列不空。 } [算法讨论]算法中假定栈s1和栈s2容量相同。 出队从栈s2出,当s2为空时,若s1不空,则将s1倒入s2再出栈。 入队在s1,当s1满后,若s2空,则将s1倒入s2,之后再入队。 因此队列的容量为两栈容量之和。 元素从栈s1倒入s2,必须在s2空的情况下才能进行,即在要求出队操作时,若s2空,则不论s1元素多少(只要不空),就要全部倒入s2中。 第5章数组和广义表 1.稀疏矩阵压缩存储后,必会失去随机存取功能。 () 2.数组是同类型值的集合。 () 3.数组可看成线性结构的一种推广,因此与线性表一样,可以对它进行插入,删除等操作。 () 4.一个稀疏矩阵Am*n采用三元组形式表示,若把三元组中有关行下标与列下标的值互换,并把m和n的值互换,则就完成了Am*n的转置运算。 () 5.二维以上的数组其实是一种特殊的广义表。 () 6.广义表的取表尾运算,其结果通常是个表,但有时也可是个单元素值。 () 7.若一个广义表的表头为空表,则此广义表亦为空表。 () 8.广义表中的元素或者是一个不可分割的原子,或者是一个非空的广义表。 () 9.所谓取广义表的表尾就是返回广义表中最后一个元素。 () 10.一个广义表可以为其它广义表所共享。 () 11.设二维数组A[-20..30,-30..20],每个元素占有4个存储单元,存储起始地址为200.如按行优先顺序存储,则元素A[25,18]的存储地址为__ (1)_;如按列优先顺序存储,则元素A[-18,-25]的存储地址为__ (2)_。 12.已知二维数组A[1..10,0..9]中每个元素占4个单元,在按行优先方式将其存储到起始地址为1000的连续存储区域时,A[5,9]的地址是: _______。 13.设数组A[0..8,1..10],数组中任一元素A[i,j]均占内存48个二进制位,从首地址2000开始连续存放在主内存里,主内存字长为16位,那么 (l)存放该数组至少需要的单元数是_______; (2)存放数组的第8列的所有元素至少需要的单元数是_______; (3)数组按列存储时,元素A[5,8]的起始地址是_______。 答案: 1.对 2.错误。 数组是具有相同性质的数据元素的集合,数据元素不仅有值,还有下标。 因此,可以说数祖是元素值和下标构成的偶对的有穷集合。 3.错误。 数组在维数和界偶确定后,其元素个数已经确定,不能进行插入和删除运算。 4.错误。 稀疏矩阵转置后,除行列下标及行列数互换外,还必须确定该元素转置后在新三元组中的位置。 5.对 6.错误。 广义表的取表尾运算,是非空广义表除去表头元素,剩余元素组成的表,不可能是原子。 7.错误。 广义表的表头就是广义表的第一个元素。 只有非空广义表才能取表头。 8.错误。 广义表中元素可以是原子,也可以是表(包括空表和非空表)。 9.错误。 广义表的表尾,指去掉表头元素后,剩余元素所组成的表。 10.对 11. (1)9572 (2)1228 12.1196 13. (1)270 (2)27(3)2204 第6章树和二叉树 1.一棵树高为K的完全二叉树至少有()个结点。 A.2k–1B.2k-1–1C.2k-1D.2k 2.对二叉树的结点从1开始进行连续编号,要求每个结点的编号大于其左、右孩子的编号,同一结点的左右孩子中,其左孩子的编号小于其右孩子的编号,可采用()次序的遍历实现编号。 A.先序B.中序C.后序 D.从根开始按层次遍历 3.在下列存储形式中,哪一个不是树的存储形式? () A.双亲表示法B.孩子链表表示法 C.孩子兄弟表示法D.顺序存储表示法 4.二叉树的先序遍历和中序遍历如下: 先序遍历: EFHIGJK;中序遍历: HFIEJKG。 该
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 综合