算法和数据结构C语言版课后习题集答案解析(机械工业出版社)第34章习题集参考答案解析
算法与数据结构C语言习题参考答案章
绪论1.将下列复杂度由小到大重新排序:A.2n B.n C.n5D.10 000 E.n*log2 n答10 000< n*log2n< n5< 2n < n2.将下列复杂度由小到大重新排序:A.n*log2n B.n + n2 + n3C.24D.n0.5答24< n0.5< n*log2 n < n + n2 + n33.用大“O”表示法描述下列复杂度:A.5n5/2 + n2/5 B.6*log2n + 9nC.3n4+ n* log2n D.5n2 + n3/2答A:O n5/2B:O n C:O n4D:O n24.按照增长率从低到高的顺序排列以下表达式:4n2 ; log3n; 3n ; 20n ; 2000 ; log2n ; n2/3..又n应排在第几位答按照增长率从低到高依次为:2000; log3n; log2n ; n2/3 ; 20n ; 4n2 ; 3n..n的增长率比它们中的每一个都要大;应排在最后一位..5. 计算下列程序片断的时间代价:int i=1;whilei<=n{printf“i=%d\n”;i;i=i+1;}答循环控制变量i从1增加到n;循环体执行n次;第一句i的初始化执行次数为1;第二句执行n次;循环体中第一句printf执行n次;第二句i从1循环到n;共执行n次..所以该程序段总的时间代价为:Tn = 1 + n + 2n = 3n+ 1 = On6. 计算下列程序片断的时间代价:int i=1;whilei<=n{int j=1;whilej<=n{int k=1;whilek<=n{printf“i=%d;j=%d;k=%d\n”;I;j;k;k=k+1;}j=j+1;}i=i+1;}答循环控制变量i从1增加到n;最外层循环体执行n次;循环控制变量j从1增加到n;中间层循环体执行n次;循环控制变量k从1增加到n;最内层循环体执行n次;所以该程序段总的时间代价为:Tn = 1 + n + n{1 + n + n1 + n + 2n +1 +1 +1}+ 1= 3n3 + 3n2 +4n +2= On32. 线性表1.试写一个插入算法int insertPost_seqpalist; p; x ;在palist所指顺序表中;下标为p的元素之后;插入一个值为x的元素;返回插入成功与否的标志..答数据结构采用2.1.2节中顺序表定义..int insertPost_seqPseqList palist; int p; DataType x {/* 在palist所指顺序表中下标为p的元素之后插入元素x */int q;if palist->n >= palist-> MAXNUM { /* 溢出*/printf“Overflow\n”;return 0;}if p<0 || p>palist->n-1 { /* 不存在下标为p的元素*/printf“N ot exist \n”; return 0;}forq=palist->n - 1; q>=p+1; q-- /* 插入位置及之后的元素均后移一个位置*/palist->elementq+1 = palist->elementq;palist->elementp+1 = x; /* 插入元素x */palist->n = palist->n + 1; /* 元素个数加1 */return 1;}2试写一个删除算法deleteV_seqpalist; x ;在palist所指顺序表中;删除一个值为x的元素;返回删除成功与否的标志..答数据结构采用2.1.2节中顺序表定义..int deleteV_seqPseqList palist; p; DataType x {/* 在palist所指顺序表中删除值为x的元素*/int p;q;forp=0;p<n;p++ /*查找值为x的元素的下标*/ifx==palist->elementp{forq=p; q<palist->n-1; q++ /* 被删除元素之后的元素均前移一个位置*/palist->elementq = palist->elementq+1;palist->n = palist->n - 1; /* 元素个数减1 */return 1 ;}return 0;}3. 设有一线性表e = e0; e1 ; e2 ; …; e n 1 ;其逆线性表定义为e = e n 1 ; …; e2 ; e1 ;e0..请设计一个算法;将用顺序表表示的线性表置逆;要求逆线性表仍占用原线性表的空间..答数据结构采用2.1.2节中顺序表的定义..思路考虑对数组element 进行置逆;即把第一个元素和最后一个元素换位置;把第二个元素和倒数第二个元素换位置……..注意这种调换的工作只需对数组的前一半元素进行;所以设置整数变量count用于存放数组长度的一半的值..大家可以考虑一下:为什么不能对整个数组进行如上的对元素“换位置”的工作提示:这样会将本来已经置逆的线性表又置逆回来;即又变成了原来的表..顺序表的置逆算法void rev_seqPSeqList palist{DataType x;int count; i;if palist->n == 0 || palist->n == 1 return; /*空表或只有一个元素;直接返回*/count = palist->n / 2;for i = 0; i < count; i++{ /*只需调换半个表的元素*/x = palist->elementi;palist->elementi = palist->elementpalist->n 1 i;palist->elementpalist->n 1 i = x;}}代价分析该算法中包含一个for循环;其循环次数为n/2..因此;算法的时间代价为On..4. 已知长度为n的线性表A采用顺序存储结构;请写一算法;找出该线性表中值最小的数据元素.. 答数据结构采用2.1.2节中顺序表定义..思路设置变量min;遍历整个表;不断更新当前已经经历过的元素的最小值即可..为方便起见;事先假设表不为空..算法DataType min_seqPSeqList palist{ /*求非空顺序表中的最小数据元素*/DataType min;int i;min = palist->element0; /*初始化min*/for i = 1; i < palist->n; i++ /*min中保存的总是当前的最小数据*/if min > palist->elementimin = palist->elementi;return min;}代价分析该算法访问顺序表中每个元素各一次;时间代价为On..讨论读者可以试图对上面的算法进行修改;使返回的值不是最小元素的值而是它的下标..5. 已知线性表A的长度为n;并且采用顺序存储结构..写一算法;删除线性表中所有值为x的元素.. 答数据结构采用2.1.2节中顺序表的定义..思路为了减少移动次数;可以采用快速检索的思想;用两个变量i; j记录顺序表中被处理的两端元素的下标;开始时i = 0;j = n 1;边检索第i个元素边增加i;直到找到一个元素值等于x;再边检索第j个元素边减少j;直到找到一个元素值不等于x;把下标为j的元素移到下标为i的位置后重复上述过程;直到i≥j..另用一变量count记录删除了多少个元素..算法void delx_seqPSeqList p; DataType x{/*删除顺序表中所有值为x的元素;新顺序表可能不保持原有顺序*/int i = 0; j = p->n 1; count = 0; /*i定位于顺序表开始处;j定位于顺序表最后*/while i < j {if p->elementi == x { /*找到了一个要删除的元素*/while p->elementj == x && i = j {/*从后往前找不会被删除的元素;当i; j相等时退出循环;count记录从后往前找的过程中遇到了多少个要删的元素*/j ;count++;}if i = = j {p->n = p->n count 1;return;}else{p->elementi = p->elementj;count++;j ;}}i++;}p->n = p->n count;if p->elementi == x p >n ;}代价分析该算法访问顺序表中每个元素各一次;时间代价为O n..讨论这个算法使用了一点技巧使得在中间删除元素时;避免了最后一串元素的移动..但是;它破坏了原来线性表中元素之间的顺序关系..如果需要保持原来的顺序应该怎样做这里提供一种可行的思路:从前向后遍历表;如果元素不是x;则继续向后;如果元素是x;则寻找其后第一个不是x的元素;将这两个元素互换..具体算法请读者自己实现..6.写一算法;在带头结点的单链表llist中;p所指结点前面插入值为x的新结点;并返回插入成功与否的标志..答数据结构采用2.1.3节中单链表定义..思想:由于在单链表中;只有指向后继结点的指针;所以只有首先找到p所指结点的前驱结点;然后才能完成插入..而找p所指结点的前驱结点;只能从单链表的第一个结点开始;使用与locate_link 类似的方式进行搜索..算法:int insertPre_linkLinkList llist;PNode p;DataType x{/* 在llist带头结点的单链表中;p所指结点前面插入值为x的新结点*/PNode p1;ifllist==NULL return 0;p1=llist;whilep1=NULL&&p1->link=pp1=p1->link; /*寻找p所指结点的前驱结点*/ifp1=NULL return 0;PNode q=PNodemallocsizeofstruct Node;/*申请新结点*/ifq=NULL {printf“Out of space\n”;return 0;}q->info=x;q->link=p1->link;p1->link=q;return 1;}7.写一算法;在带头结点的单链表llist中;删除p所指的结点;并返回删除成功与否的标志..答数据结构采用2.1.3节中单链表定义..思想:由于在单链表中;只有指向后继结点的指针;所以只有首先找到p所指结点的前驱结点;然后才能完成删除..而找p所指结点的前驱结点;只能从单链表的第一个结点开始;使用与locate_link 类似的方式进行搜索..int deleteP_linkLinkList llist;PNode p{/* 在llist带头结点的单链表中;删除p所指的结点*/PNode p1;ifllist==NULLreturn Null;p1=llist;whilep1=NULL&&p1->link=pp1=p1->link; /*寻找p所指结点的前驱结点*/ifp1=NULLreturn 0;p1->link=p->link;freep; /* 删除结点p */return 1;}8. 已知list是指向无头结点的单链表的指针变量;写出删除该链表下标为i的第i+1个结点的算法..答数据结构采用2.1.3节中单链表定义..思路依次遍历表中的每一个结点并计数;到第i+1个结点时实行删除..由于链表是无头结点的;所以在删除第一个结点时要特别注意..算法int deleteindex_link_noheadLinkList * pllist; int i {/*删除单链表中下标为i的结点..删除成功返回TRUE;否则返回FALSE..*/int j;PNode p; q;if *pllist == NULL || i < 0 return FALSE;if i = = 0 { /*如果需要删除第一个结点*/q = *pllist;*pllist = *pllist->link;freeq;return TRUE;}p = *pllist;j = 0;while p->link = NULL && j < i 1 { /*寻找下标为i 1的结点的地址*/ p = p->link;j++;}if p->link == NULL return FALSE; /*此元素不存在*/q = p->link;p->link = q->link;freeq;return TRUE;}代价分析该算法访问单链表中前面i个结点;时间代价为Oi;最大不超过On..讨论如果函数参数不是LinkList *类型而是LinkList类型;在删除i=0的结点时;程序不能正确实现;其原因请读者思考考虑C语言的参数传递方式..如果单链表带表头结点;重写本题的算法..比较这两个算法;是否能体会到表头结点的作用..9. 已知list是指向无头结点的单链表的指针变量;写出删除该链表中从下标为i的第i+1个结点开始的连续k个结点的算法..答数据结构采用2.1.3节单链表定义..思路这道题与上题相似;只需要增加计数即可..要注意的是应该判断给出的i和k是否合理;是不是会超出链表长度..算法int del_link_noheadLinkList * pllist; int i; int k {/*删除单链表中从下标i开始的k个结点..删除成功返回TRUE;否则返回FALSE..*/int j;PNode p; q;if *pllist == NULL || i < 0 || k <= 0 return FALSE;if i = = 0 { /*如果需要删除从第一个结点开始的k个结点*/for j = 0; j < k && *pllist = NULL; j++ {q = *pllist;*pllist = *pllist->link;freeq;}return TRUE;}p = *pllist;j = 0;while p->link = NULL && j < i 1 { /*寻找下标为i 1的结点的地址*/p = p->link;j++;}if p->link == NULL return FALSE; /*第i个结点不存在*/for j = 0; j < k && p->link = NULL; j++ {q = p->link;p->link = q->link;freeq;}return TRUE;}代价分析该算法访问单链表中前面i+k个结点;时间代价为Oi+k;最大不超过On..13. 请设计一个算法;求出循环表中结点的个数..答数据结构采用不带头结点的循环链表..struct Node;typedef struct Node * PNode;struct Node{DataType info;PNode link;};typedef struct Node * LinkList;思路遍历整个循环链表;同时计数即可..错误算法int countLinkList clist{int count;PNode p; q;p = clist;q = p->link;if clist == NULL return 0; /*如果是空表*/count = 1;while q = p{q = q->link;count++;}return count;}错误:如果clist是一个空表;那么第5行的语句“q = p->link;”是非法的..分析:应把第6行语句用下划线表示提前1行或2行..一定要放在语句“q = p->link;”之前..缺点:增加局部变量p..分析:这样做没有必要;因为p的初值置为clist;在程序中并没有对p做其他修改;所以程序中不需要引入p而直接使用clist即可..算法int countLinkList clist{int count;PNode q;if clist == NULL return 0; /*如果是空表*/q = clist->link;count = 1;while q = clist{q = q->link;count++;}return count;}代价分析该算法访问循环链表中每个结点各一次;时间代价为On..4. 栈与队列1. 写一个递归算法来把整数字符串转换为整数..例:“43567”→43567..答思路先递归调用本算法转换除去末位外剩余的字符串;结果乘以10..再转换末位..将两结果相加即为所求..算法int stringToInt1char * s; int start; int end {/*把整数字符串s中从start到end的部分转换为整数*/if start > end return 1; /*转换失败*/if start == end return send '0'; /*只有一个字符;直接转换*/return stringToInt1s; start; end 1 * 10 + send '0'; /*先转换其他位;再转换末位*/}int stringToIntchar * s { /*把整数字符串s转换为整数*/int i = 0;while si = '\0' i++; /*计算字符串的长度*/return stringToInt1s; 0; i 1;}代价分析设n为字符串的长度..该算法访问每个字符各一次;时间代价为On;计算字符串的长度的时间代价也为On..故总的时间代价为On..递归算法需要栈的支持;栈的大小与递归调用的深度成正比..所以实际空间开销为On..2. 编写一个算法;对于输入的十进制非负整数;将它的二进制表示打印出来..答数据结构采用4.1.2节中栈的顺序表示..思路将输入的十进制数字反复除以2;直到它变为0..将每次的数字模2的余数入栈..栈中存放的就是所要求的二进制表示..再将栈中的元素依次弹出打印即可..算法void print_binint dec_number {/*将十进制非负整数转化为二进制数打印出来*/PSeqStack pastack; int temp = dec_number; if temp < 0 {printf"Error\n"; return;}pastack = createEmptyStack_seq; /*建立一个空栈*/ if pastack == NULL return; while temp > 0 {push_seqpastack; temp % 2; temp /= 2;}whileisEmptyStack_seqpastack {printf"%d"; top_seqpastack; pop_seqpastack;}freepastack;}代价分析设输入的十进制数字为n ;则算法的时间代价为O n 2log ..空间代价主要是栈的大小;为O n 2log .. 3.写一个算法:PSeqStack createEmptyStack_seq int m 创建一个空栈..数据结构采用4.1.2节中栈的顺序表示..PSegStack createEmptyStack_seqint m{ /* 创建一个空栈 */PSeqStack pastack = PSeqStackmallocsizeofstruct SeqStack; if pastack=NULL{ pastack ->s = DataType*mallocsizeofDataType*m;if pastack ->s{pastack ->MAXNUM=m; pastack ->t= -1;/* 栈顶变量赋值为-1 */return pastack ; }else free pastack; }printf “Out of space\n”; /* 存储分配失败 */return NULL;}4;写一个算法:int isEmptyStack_seq PSeqStack pastack 判断pastack所指的栈是否为空栈..数据结构采用4.1.2节中栈的顺序表示..int isEmptyStack_seqPSeqStack pastack{/* 判断pastack所指的栈是否为空栈*/ifpastack->t == -1 return 1;else return 0;}8. 假设以循环链表表示队列;并且只设一个指针指向队尾元素结点注意不设队头指针;试编写相应的创建空队列、入队列和出队列的算法..答数据结构采用不带头结点的循环链表表示队列..struct Node;typedef struct Node * PNode;struct Node {DataType info;PNode link;};struct ClinkQueue { /*循环链表表示的队列类型*/PNode r; /*尾指针*/}typedef struct ClinkQueue * PClinkQueue; /*指向循环链表表示的队列的指针类型*/ 思路与队列的单链表表示相似;但节省了指向队头的指针变量;所以在需要找表头结点时必须通过表尾指针进行..算法PClinkQueue createEmptyQueue_clink { /*创建空队列*/PClinkQueue pcqu = PClinkQueuemallocsizeofstruct ClinkQueue;pcqu->r = NULL;return pcqu;}void enQueue_clinkPClinkQueue pcqu; DataType x { /*进队列*/PNode p;p = PNodemallocsizeofstruct Node;p->info = x;if pcqu->r == NULL {pcqu->r = p;p->link = p;return;} /*进空队列;即往空队列中加入第一个结点*/p->link = pcqu->r->link;pcqu->r->link = p;pcqu->r = p;}void deQueue_clinkPClinkQueue pcqu { /*出队列*/PNode p;if pcqu->r == NULL { /*是空队列*/printf"Underflow\n";return;}if pcqu->r->link == pcqu->r { /*只有一个元素的队列*/freepcqu->r;pcqu->r = NULL;return;}p = pcqu->r->link; /*指向队头*/pcqu->r->link = p->link;freep;}代价分析上述几个算法都不包含循环;只有常数条语句;因此每个算法的时间代价均为O1..讨论本题可以看成队列的循环表实现..5. 二叉树与树1. 写一个算法来计算给定二叉树的叶结点数..答数据结构采用5.1.3节中二叉树的链接表示..算法int num_of_leavesBinTree t { /*计算二叉树的叶结点个数*/if t = = NULL return 0; /*空树;返回0*/if t->llink = = NULL && t->rlink = = NULL return 1; /*根结点是树叶;返回1*/return num_of_leavest->llink + num_of_leavest->rlink;/*返回“左子树的叶结点数+右子树的叶结点数”*/}代价分析该算法访问每个结点各一次;时间代价为On..空间代价为Oh..2. 假设二叉树采用链接方法存储;编写一个计算一棵二叉树t的高度的函数..数据结构采用5.1.3节中二叉树的链接表示..思路对一棵二叉树t;考察它左右子树的高度;取其中大的一个;再加1即为t的高度..算法int depthBinTree t{PBinTreeNode pbtree;int dl; dr;pbtree = t;if pbtree = = NULL{return 1;}dl = depthpbtree->llink;dr = depthpbtree->rlink;return dl > dr dl : dr + 1;}代价分析设树中的结点个数为n;递归访问次数只可能是n..所以;时间代价为On..空间代价为Oh..h为二叉树的高度..6. 设计一个程序;根据二叉树的先根序列和对称序序列创建一棵用左右指针表示的二叉树..答数据结构采用5.1.3节中二叉树的链接表示..思路二叉树的先根序列和对称序序列;用两个数组preorder和inorder存放..先根序列的第一个元素的值preorder0应为二叉树的根上的元素值;在另一个数组中查到此值;设为inorder k..此时;数组preorder中从preorder1到preorder k的序列长度为k和数组inorder中从inorder0到inorder k 1长度为k的序列;恰好分别是根结点左子树k个结点的先根序列和对称序序列..数组preorder中从preorder k+1到preorder n 1的序列长度为n k 1和数组inorder中从inorder k+1到inorder n 1长度为n k 1的序列;恰好分别是根结点左子树n k 1个结点的先根序列和对称序序列..根据上述分析;算法先创建根结点;再递归调用自己两次来分别创建左右子树..int create_BTreePBinTree pbtree; DataType * preorder; DataType * inorder; int n{/*根据先根序列preorder和对称序序列inorder长度为n创建二叉树pbtree..对于正确的先根序列和对称序序列;算法返回TRUE;否则返回FALSE..*/int i; k;int tag1; tag2;if n = = 0 {*pbtree = NULL;return TRUE;}for i = 0; i < n; i++if inorderi = = preorder0break;if i = = n {*pbtree = NULL;return FALSE; /*输入的先根序列或对称序序列有误;创建失败*/ }k = i;*pbtree = PBinTreeNodemallocsizeofstruct BinTreeNode;*pbtree->info = preorder0;tag1 = create_BTree&*pbtree->llink; preorder + 1; inorder; k;/*递归调用本算法创建左子树*/tag2 = create_BTree&*pbtree->rlink; preorder + k + 1; inorder + k + 1; n k 1;/*递归调用本算法创建右子树*/if tag1 = = TRUE && tag2 = = TRUE return TRUE;return FALSE; /*二叉树创建成功当且仅当其左右子树都创建成功*/ }代价分析最坏的情况是;每个非叶结点只有左子树..这时两个数组之间需要比较n+n-1+…+1=On2次..所以;该算法的时间代价为On2..空间代价主要包括:存放二叉树的空间On和用于递归调用的栈空间不超过On..7. 试设计树的子表表示法的存储结构;并给出在这种表示基础上主要运算的实现算法..答数据结构struct EdgeNode /*边表中结点的定义*/{int nodeposition; /*子结点位置*/struct EdgeNode * link; /*下一个边的指针*/};struct ChiTreeNode /*结点的定义*/{DataType info; /*结点本身信息*/struct EdgeNode * children; /*到子结点的边表*/};struct ChiTree /*树的定义*/{struct ChiTreeNode nodelistMAXNUM; /*结点表*/int root; /*根的位置*/int n; /*结点的个数*/ };typedef struct ChiTree * PChiTree;算法创建空树PChiTree CreateNullTree_chitreevoid{PChiTree p;p = PChiTreemallocsizeofstruct ChiTree;if p = = NULLprintf"Out of space\n";else{p->n=0;p->root = 1;}return p;}判断树是否为空int isNull_chitree PChiTree t{return t->n = = 0;}返回非空树的根结点的下标DataType root_chitree PChiTree t{return t->root;}返回下标为p的结点的父结点的下标int parent_chitree PChiTree t; int p{int i;struct EdgeNode * v;if p < 0 || p >= t->n return 1;for i = 0; i < t->n; i++{v = t->nodelisti.children;while v = NULLif v->nodeposition = = preturn i;elsev = v->link;}return 1;}返回下标为p的结点的最左子结点的下标int leftChild_chitreePParTree t; int p{struct EdgeNode * v;if p < 0 || p >= t->n return 1;v = t->nodelisti.children;if v = = NULL return 1;return v->nodeposition;}返回下标为p的结点的右兄弟结点的下标int rightSibling_chitreePParTree t; int p{int i;struct EdgeNode * v;if p < 0 || p >= t->n return 1; /*没有下标为p的结点*/for i = 0; i < t->n; i++ /*for循环每次检查结点下标中一个元素*/{v = t->nodelisti.children;while v = NULL /*每次循环检查结点i的边表中的一个元素*/if v->nodeposition = = pifv->link = = NULLreturn 1; /*没有右兄弟结点*/elsereturn v->link->nodeposition; /*返回右兄弟结点在结点表中的位置*/ elsev=v->link;}return 1; /*没有右兄弟结点*/}代价分析这是一个两重循环程序;外层循环最多执行n次;内层循环对每个结点的子结点进行检查;子结点的个数最大可能与n接近;所以表面看来这是一个n2阶的时间代价;但是;仔细分析内层的循环体;可以看出内层循环最多对树中的每条边执行一次;由于树中边的个数与结点的个数成正比;所以时间代价仍然是On..补充题:1. 试设计完全二叉树的顺序表示法的存储结构;并给出在这种表示基础上主要运算的实现算法.. 答数据结构struct SeqBTree{DataType nodelistMAXNODE;int n; /*完全二叉树的结点个数*/};typedef struct SeqBTree * PSeqBTree;算法判断二叉树是否为空int isNull_seqPSeqBTree t{return t->n = = 0;}返回非空二叉树的根结点的下标int root_seqPSeqBTree t{return 0;}返回下标为p的结点的父结点的下标int parent_seqPSeqBTree t; int p{if p < 0 || p >= t->n return 1;return p 1 / 2;}返回下标为p的结点的左子结点的下标int leftChild_seqPSeqBTree t; int p{if p < 0 || p >= t->n return 1;return 2*p + 1;}返回下标为p的结点的右子结点的下标int rightChild_seqbtreePSeqBTree t; int p{if p < 0 || p >= t->n return 1;return 2 * p + 1;}2. 试设计二叉树的左右指针表示法的存储结构;并给出在这种表示基础上主要运算的实现算法.. 答数据结构struct BinTreeNode;typedef struct BinTreeNode * PBinTreeNode;struct BinTreeNode {int info;PBinTreeNode llink;PBinTreeNode rlink;};typedef struct BinTreeNode * BinTree;算法判断二叉树是否为空int isNull_btreeBinTree t{return t = = NULL;}返回非空二叉树的根结点的地址PBinTreeNode root_btreeBinTree t{return t;}返回二叉树t中结点p的父结点的地址PBinTreeNode parent_btreePBinTreeNode p; BinTree t{PBinTreeNode r;if p = = NULL return NULL;if p = = t || t = = NULL return NULL;if t->llink = = p || t->rlink = = p return t;r = parent_btreep; t->llink; /*递归调用*/if r = NULL return r;r = parent_btreep; t->rlink; /*递归调用*/if r = NULL return r;return NULL;}返回结点p的左子结点的地址PBinTreeNode leftChild_btreePBinTreeNode p{if p = = NULL return NULL;return p->llink;}返回结点p的右子结点的地址PBinTreeNode rightChild_btreePBinTreeNode p{if p = = NULL return NULL;return p->rlink;}。
算法与数据结构习题及参考答案
算法与数据结构习题及参考答案一、选择题1. 在算法分析中,时间复杂度表示的是:A. 算法执行的时间B. 算法的运行速度C. 算法执行所需的操作次数D. 算法的内存消耗答案:C2. 哪种数据结构可以在常数时间内完成插入和删除操作?A. 数组B. 栈C. 队列D. 链表答案:B3. 单链表的逆置可以使用哪种算法实现?A. 冒泡排序B. 归并排序C. 快速排序D. 双指针法答案:D4. 常用的查找算法中,哪种算法的时间复杂度始终为O(log n)?A. 顺序查找B. 二分查找C. 广度优先搜索D. 深度优先搜索答案:B5. 哪种排序算法的时间复杂度最坏情况下仍为O(n log n)?A. 冒泡排序B. 插入排序C. 快速排序D. 堆排序答案:C二、填空题1. 下面哪个数据结构先进先出?A. 栈B. 队列C. 堆D. 链表答案:B2. 在快速排序的基本步骤中,需要选取一个元素作为________。
答案:枢纽元素3. 广度优先搜索使用的数据结构是________。
答案:队列4. 二分查找是基于_________的。
答案:有序数组5. 哈希表的查找时间复杂度为_________。
答案:O(1)三、解答题1. 请简要说明冒泡排序算法的原理及时间复杂度。
答:冒泡排序是一种简单直观的排序算法。
它的基本思想是通过相邻元素之间的比较和交换来将最大(或最小)的元素逐渐“冒泡”到数列的一端。
冒泡排序的过程如下:1)比较相邻的元素,如果前面的元素大于后面的元素,则交换它们的位置;2)对每一对相邻元素重复进行比较和交换,直到最后一对元素;3)针对剩下的元素重复上述步骤,直到整个数列有序。
冒泡排序的时间复杂度为O(n^2),其中n为待排序数列的长度。
在最坏情况下,冒泡排序需要进行n-1次比较和交换操作,因此时间复杂度为O(n^2)。
在最好情况下,如果待排序数列已经有序,冒泡排序只需进行n-1次比较,没有交换操作,时间复杂度为O(n)。
数据结构(c语言版)课后习题答案完整版
数据结构(c语言版)课后习题答案完整版数据结构(C语言版)课后习题答案完整版一、数据结构概述数据结构是计算机科学中一个重要的概念,用来组织和存储数据,使之可以高效地访问和操作。
在C语言中,我们可以使用不同的数据结构来解决各种问题。
本文将提供完整版本的C语言数据结构的课后习题答案。
二、顺序表1. 顺序表的定义和基本操作顺序表是一种线性表,其中的元素在物理内存中连续地存储。
在C 语言中,我们可以通过定义结构体和使用指针来实现顺序表。
以下是顺序表的一些基本操作的答案:(1)初始化顺序表```ctypedef struct{int data[MAX_SIZE];int length;} SeqList;void InitList(SeqList *L){L->length = 0;}```(2)插入元素到顺序表中```cbool Insert(SeqList *L, int pos, int elem){if(L->length == MAX_SIZE){return false; // 顺序表已满}if(pos < 1 || pos > L->length + 1){return false; // 位置不合法}for(int i = L->length; i >= pos; i--){L->data[i] = L->data[i-1]; // 向后移动元素 }L->data[pos-1] = elem;L->length++;return true;}```(3)删除顺序表中的元素```cbool Delete(SeqList *L, int pos){if(pos < 1 || pos > L->length){return false; // 位置不合法}for(int i = pos; i < L->length; i++){L->data[i-1] = L->data[i]; // 向前移动元素 }L->length--;return true;}```(4)查找顺序表中的元素```cint Search(SeqList L, int elem){for(int i = 0; i < L.length; i++){if(L.data[i] == elem){return i + 1; // 找到元素,返回位置 }}return -1; // 未找到元素}```2. 顺序表习题解答(1)逆置顺序表```cvoid Reverse(SeqList *L){for(int i = 0; i < L->length / 2; i++){int temp = L->data[i];L->data[i] = L->data[L->length - 1 - i]; L->data[L->length - 1 - i] = temp;}}```(2)顺序表元素去重```cvoid RemoveDuplicates(SeqList *L){for(int i = 0; i < L->length; i++){for(int j = i + 1; j < L->length; j++){if(L->data[i] == L->data[j]){Delete(L, j + 1);j--;}}}}```三、链表1. 单链表单链表是一种常见的链式存储结构,每个节点包含数据和指向下一个节点的指针。
数据结构(C语言版本)课后练习答案的完整版本.doc
数据结构(C语言版本)课后练习答案的完整版本第一章引言5。
选择题:CCBDCA 6。
尝试分析以下程序段的时间复杂性。
(1)o(1)(2)o(m * n)(3)o(N2)(4)o(log3n)(5)因为x已执行n-1n-2.1=n (n-1)/2,执行时间为O(n2)(6)O()第2章线性表1。
多项选择babadbcbdcddac 2。
算法设计问题(6)设计一种算法,通过一次遍历来确定单个链表中具有最大值的节点。
元素类型最大值(链表L ){如果(下一个==空)返回空;pmax=1-下一个;//假设第一个节点中的数据具有最大值p=L-下一个-下一个;同时(p!=NULL ){//如果在下一个节点处存在if(p-数据pmax-数据)pmax=p;p=p-下一个;}返回pmax-数据;(7)设计一种算法,通过遍历一次来反转链表中所有节点的链接方向,并且仍然使用原表的存储空间。
空逆(链表L) {//逆单个链表L p=L-头节点的下一个;下一个=空;而(p){ q=p-next;//q指向*p=l-next 的下一个p-next;l-next=p;//*p插入在头节点p=q之后;}}(10)已知长度n的线性表A采用顺序存储结构。
请编写一个时间复杂度为0(n)和空间复杂度为0(1)的算法,删除线性表中所有有值项的数据元素。
[主题分析]删除线性表中按顺序存储的元素通常涉及一系列元素的移动(删除第I个元素,并按顺序向前移动第I到第N个元素)。
本主题要求删除线性表中项目值为的所有数据元素,并且不要求元素之间的相对位置保持不变。
因此,可以考虑设置两个指针(i=1,j=n)从两端移到中间。
当遇到带有值项的数据元素时,右端元素将直接移动到带有值项的数据元素的位置。
虚删除(元素类型A[),整数n)A是一个有n个元素的一维数组。
此算法删除值为项的中的所有元素。
{ I=1;j=n。
∑设置数组的低端和高端指针(下标)。
同时(不精确;r=p;//让r 作为指针,而(q!=null){ if(q-data data)r=q;q:=q-next。
数据结构c语言版第三版习题解答
数据结构c语言版第三版习题解答数据结构 C 语言版第三版习题解答在学习计算机科学与技术的过程中,数据结构是一门非常重要的基础课程。
而《数据结构C 语言版第三版》更是众多教材中的经典之作。
其中的习题对于我们理解和掌握数据结构的概念、原理以及算法实现起着至关重要的作用。
接下来,我将为大家详细解答这本书中的一些典型习题。
首先,让我们来看一道关于线性表的习题。
题目是这样的:设计一个算法,从一个有序的线性表中删除所有其值重复的元素,使表中所有元素的值均不同。
对于这道题,我们可以采用双指针的方法来解决。
定义两个指针 p和 q,p 指向线性表的开头,q 从 p 的下一个位置开始。
当 q 所指向的元素与 p 所指向的元素相同时,我们就将 q 所指向的元素删除,并将 q 向后移动一位。
当 q 所指向的元素与 p 所指向的元素不同时,我们将 p 向后移动一位,并将 q 所指向的元素赋值给 p 所指向的位置,然后再将 q 向后移动一位。
当 q 超出线性表的范围时,算法结束。
下面是用 C 语言实现的代码:```cvoid removeDuplicates(int arr, int n) {int p = 0, q = 1;while (q < n) {if (arrp == arrq) {for (int i = q; i < n 1; i++){arri = arri + 1;}(n);} else {p++;arrp = arrq;}q++;}}```再来看一道关于栈的习题。
题目是:利用栈实现将一个十进制数转换为八进制数。
我们知道,将十进制数转换为八进制数可以通过不断除以 8 取余数的方法来实现。
而栈的特点是后进先出,正好适合存储这些余数。
以下是 C 语言实现的代码:```cinclude <stdioh>include <stdlibh>define MAX_SIZE 100typedef struct {int top;int dataMAX_SIZE;} Stack;//初始化栈void initStack(Stack s) {s>top =-1;}//判断栈是否为空int isEmpty(Stack s) {return s>top ==-1;}//判断栈是否已满int isFull(Stack s) {return s>top == MAX_SIZE 1;}//入栈操作void push(Stack s, int element) {if (isFull(s)){printf("Stack Overflow!\n");return;}s>data++s>top = element;}//出栈操作int pop(Stack s) {if (isEmpty(s)){printf("Stack Underflow!\n");return -1;}return s>datas>top;}//将十进制转换为八进制void decimalToOctal(int decimal) {Stack s;initStack(&s);while (decimal!= 0) {push(&s, decimal % 8);decimal /= 8;}while (!isEmpty(&s)){printf("%d", pop(&s));}printf("\n");}int main(){int decimal;printf("请输入一个十进制数: ");scanf("%d",&decimal);printf("转换后的八进制数为: ");decimalToOctal(decimal);return 0;}```接下来是一道关于队列的习题。
数据结构(C语言版)习题参考答案
数据结构(C语言版)习题参考答案数据结构(C语言版)习题参考答案1. 数据结构简介数据结构是计算机科学中重要的概念之一,它关注如何组织和存储数据,以便有效地进行访问和操作。
C语言是一种广泛应用于数据结构实现的编程语言。
本文将提供一些常见数据结构习题的参考答案,帮助读者理解和掌握数据结构的基本概念与实现。
2. 数组数组是一种线性结构,存储具有相同数据类型的元素。
以下是一些数组习题的参考答案:2.1 统计数组中某个元素出现的次数```int countOccurrences(int arr[], int n, int x) {int count = 0;for (int i = 0; i < n; i++) {if (arr[i] == x) {count++;}}return count;}```2.2 查找数组中的最大值和最小值```void findMinMax(int arr[], int n, int* min, int* max) { *min = arr[0];*max = arr[0];for (int i = 1; i < n; i++) {if (arr[i] < *min) {*min = arr[i];}if (arr[i] > *max) {*max = arr[i];}}}```3. 链表链表是一种动态数据结构,每个节点包含数据和指向下一个节点的指针。
以下是一些链表习题的参考答案:3.1 反转链表```Node* reverseLinkedList(Node* head) {Node* prev = NULL;Node* curr = head;while (curr != NULL) {Node* next = curr->next;curr->next = prev;prev = curr;curr = next;}return prev;}```3.2 合并两个有序链表```Node* mergeLists(Node* list1, Node* list2) {if (list1 == NULL) {return list2;}if (list2 == NULL) {return list1;}if (list1->data < list2->data) {list1->next = mergeLists(list1->next, list2);return list1;} else {list2->next = mergeLists(list1, list2->next);return list2;}}```4. 栈和队列栈和队列是两种重要的线性数据结构,栈支持后进先出(LIFO),队列支持先进先出(FIFO)。
数据结构(C语言版)课后习题答案
第1章绪论1.简述下列概念:数据、数据元素、数据项、数据对象、数据结构、逻辑结构、存储结构、抽象数据类型。
答案:数据:是客观事物的符号表示,指所有能输入到计算机中并被计算机程序处理的符号的总称。
如数学计算中用到的整数和实数,文本编辑所用到的字符串,多媒体程序处理的图形、图像、声音、动画等通过特殊编码定义后的数据。
数据元素:是数据的基本单位,在计算机中通常作为一个整体进行考虑和处理。
在有些情况下,数据元素也称为元素、结点、记录等。
数据元素用于完整地描述一个对象,如一个学生记录,树中棋盘的一个格局(状态)、图中的一个顶点等。
数据项:是组成数据元素的、有独立含义的、不可分割的最小单位。
例如,学生基本信息表中的学号、姓名、性别等都是数据项。
数据对象:是性质相同的数据元素的集合,是数据的一个子集。
例如:整数数据对象是集合N={0,±1,±2,…},字母字符数据对象是集合C={‘A’,‘B’,…,‘Z’,‘a’,‘b’,…,‘z’},学生基本信息表也可是一个数据对象。
数据结构:是相互之间存在一种或多种特定关系的数据元素的集合。
换句话说,数据结构是带“结构”的数据元素的集合,“结构”就是指数据元素之间存在的关系。
逻辑结构:从逻辑关系上描述数据,它与数据的存储无关,是独立于计算机的。
因此,数据的逻辑结构可以看作是从具体问题抽象出来的数学模型。
存储结构:数据对象在计算机中的存储表示,也称为物理结构。
抽象数据类型:由用户定义的,表示应用问题的数学模型,以及定义在这个模型上的一组操作的总称。
具体包括三部分:数据对象、数据对象上关系的集合和对数据对象的基本操作的集合。
2.试举一个数据结构的例子,叙述其逻辑结构和存储结构两方面的含义和相互关系。
答案:例如有一张学生基本信息表,包括学生的学号、姓名、性别、籍贯、专业等。
每个学生基本信息记录对应一个数据元素,学生记录按顺序号排列,形成了学生基本信息记录的线性序列。
数据结构(C语言版)第三四章习题答案解析
第3章栈和队列习题1.选择题(1)若让元素1,2,3,4,5依次进栈,则出栈次序不可能出现在()种情况。
A.5,4,3,2,1 B.2,1,5,4,3 C.4,3,1,2,5 D.2,3,5,4,1(2)若已知一个栈的入栈序列是1,2,3,…,n,其输出序列为p1,p2,p3,…,pn,若p1=n,则pi为()。
A.i B.n-i C.n-i+1 D.不确定(3)数组Q[n]用来表示一个循环队列,f为当前队列头元素的前一位置,r为队尾元素的位置,假定队列中元素的个数小于n,计算队列中元素个数的公式为()。
A.r-f B.(n+f-r)%n C.n+r-f D.(n+r-f)%n (4)链式栈结点为:(data,link),top指向栈顶.若想摘除栈顶结点,并将删除结点的值保存到x中,则应执行操作()。
A.x=top->data;top=top->link; B.top=top->link;x=top->link;C.x=top;top=top->link; D.x=top->link;(5)设有一个递归算法如下int fact(int n) { //n大于等于0if(n<=0) return 1;else return n*fact(n-1); }则计算fact(n)需要调用该函数的次数为()。
A. n+1 B. n-1 C. n D. n+2 (6)栈在()中有所应用。
A.递归调用 B.函数调用 C.表达式求值 D.前三个选项都有(7)为解决计算机主机与打印机间速度不匹配问题,通常设一个打印数据缓冲区。
主机将要输出的数据依次写入该缓冲区,而打印机则依次从该缓冲区中取出数据。
该缓冲区的逻辑结构应该是()。
A.队列 B.栈 C.线性表 D.有序表(8)设栈S和队列Q的初始状态为空,元素e1、e2、e3、e4、e5和e6依次进入栈S,一个元素出栈后即进入Q,若6个元素出队的序列是e2、e4、e3、e6、e5和e1,则栈S的容量至少应该是()。
数据结构C语言版部分习题及答案
国家计算机等级考试二级C语言公共基础知识总结第一章数据结构与算法1.1 算法算法:是指解题方案的准确而完整的描述。
算法不等于程序,也不等计算机方法,程序的编制不可能优于算法的设计。
算法的基本特征:是一组严谨地定义运算顺序的规则,每一个规则都是有效的,是明确的,此顺序将在有限的次数下终止。
特征包括:(1)可行性;(2)确定性,算法中每一步骤都必须有明确定义,不充许有模棱两可的解释,不允许有多义性;(3)有穷性,算法必须能在有限的时间内做完,即能在执行有限个步骤后终止,包括合理的执行时间的含义;(4)拥有足够的情报。
算法的基本要素:一是对数据对象的运算和操作;二是算法的控制结构。
指令系统:一个计算机系统能执行的所有指令的集合。
基本运算包括:算术运算、逻辑运算、关系运算、数据传输。
算法的控制结构:顺序结构、选择结构、循环结构。
算法基本设计方法:列举法、归纳法、递推、递归、减斗递推技术、回溯法。
算法复杂度:算法时间复杂度和算法空间复杂度。
算法时间复杂度是指执行算法所需要的计算工作量。
算法空间复杂度是指执行这个算法所需要的内存空间。
1.2 数据结构的基本基本概念数据结构研究的三个方面:(1)数据集合中各数据元素之间所固有的逻辑关系,即数据的逻辑结构;(2)在对数据进行处理时,各数据元素在计算机中的存储关系,即数据的存储结构;(3)对各种数据结构进行的运算。
数据结构是指相互有关联的数据元素的集合。
数据的逻辑结构包含:(1)表示数据元素的信息;(2)表示各数据元素之间的前后件关系。
数据的存储结构有顺序、链接、索引等。
线性结构条件:(1)有且只有一个根结点;(2)每一个结点最多有一个前件,也最多有一个后件。
非线性结构:不满足线性结构条件的数据结构。
1.3 线性表及其顺序存储结构线性表是由一组数据元素构成,数据元素的位置只取决于自己的序号,元素之间的相对位置是线性的。
在复杂线性表中,由若干项数据元素组成的数据元素称为记录,而由多个记录构成的线性表又称为文件。
数据结构c语言版课后习题答案完整版
第1章绪论5.:CCBDCA6.分析下面各程序段的复度。
1〕O〔1〕2〕O〔m*n〕3〕O〔n2〕4〕O〔log3n〕〔5〕因x++共行了n-1+n-2+⋯⋯+1=n(n-1)/2,所以行O〔n2〕〔6〕O( n)第2章线性表1.babadbcabdcddac2.算法〔6〕一个算法,通一趟遍在表中确定最大的点。
ElemTypeMax(LinkListL){if(L->next==NULL)returnNULL;pmax=L->next;// 假定第一个点中数据具有最大p=L->next->next;while(p!=NULL){// 如果下一个点存在if(p->data>pmax->data)pmax=p;p=p->next;}returnpmax->data;〔7〕一个算法,通遍一趟,将表中所有点的接方向逆,仍利用原表的存空。
voidinverse(LinkList&L){ 逆置点的表Lp=L->next;L->next=NULL;while(p){q=p->next; //q指向*p的后p->next=L->next;L->next=p; //*p插入在点之后p=q;}}〔10〕度n的性表A采用序存构,写一复度O(n)、空复度O(1)的算法,算法除性表中所有item的数据元素。
[目分析] 在序存的性表上除元素,通常要涉及到一系列元素的移〔第个元素,第i+1至第n个元素要依次前移〕。
此题要求删除线性表中所有值为item的数据元素,并未要求元素间的相对位置不变。
因此可以考虑设头尾两个指针〔 i=1,j=n〕,从两端向中间移动,凡遇到值item的数据元素时,直接将右端元素左移至值为item的数据元素位置。
void Delete 〔ElemTypeA[] ,int n〕∥A是有n个元素的一维数组,本算法删除A中所有值为item的元素。
算法与数据结构C语言版课后习题参考答案(机械工业出版社)1绪论习题详细答案
第1章概论习题参考答案一、基础知识题1.简述下列概念数据,数据元素,数据类型,数据结构,逻辑结构,存储结构,算法。
【解答】数据是信息的载体,是描述客观事物的数、字符,以及所有能输入到计算机中并被计算机程序识别和处理的符号的集合。
数据元素是数据的基本单位。
在不同的条件下,数据元素又可称为元素、结点、顶点、记录等。
数据类型是对数据的取值范围、数据元素之间的结构以及允许施加操作的一种总体描述。
每一种计算机程序设计语言都定义有自己的数据类型。
“数据结构”这一术语有两种含义,一是作为一门课程的名称;二是作为一个科学的概念。
作为科学概念,目前尚无公认定义,一般认为,讨论数据结构要包括三个方面,一是数据的逻辑结构,二是数据的存储结构,三是对数据进行的操作(运算)。
而数据类型是值的集合和操作的集合,可以看作是已实现了的数据结构,后者是前者的一种简化情况。
数据的逻辑结构反映数据元素之间的逻辑关系(即数据元素之间的关联方式或“邻接关系”),数据的存储结构是数据结构在计算机中的表示,包括数据元素的表示及其关系的表示。
数据的运算是对数据定义的一组操作,运算是定义在逻辑结构上的,和存储结构无关,而运算的实现则依赖于存储结构。
数据结构在计算机中的表示称为物理结构,又称存储结构。
是逻辑结构在存储器中的映像,包括数据元素的表示和关系的表示。
逻辑结构与计算机无关。
算法是对特定问题求解步骤的一种描述,是指令的有限序列。
其中每一条指令表示一个或多个操作。
一个算法应该具有下列特性:有穷性、确定性、可行性、输入和输出。
2.数据的逻辑结构分哪几种,为什么说逻辑结构是数据组织的主要方面?【解答】数据的逻辑结构分为线性结构和非线性结构。
(也可以分为集合、线性结构、树形结构和图形即网状结构)。
逻辑结构是数据组织的某种“本质性”的东西:(1)逻辑结构与数据元素本身的形式、内容无关。
(2)逻辑结构与数据元素的相对位置无关。
(3)逻辑结构与所含数据元素的个数无关。
数据结构c语言版课后习题答案
数据结构c语言版课后习题答案数据结构是计算机科学中的一个重要概念,它涉及到组织、管理和存储数据的方式,以便可以有效地访问和修改数据。
C语言是一种广泛使用的编程语言,它提供了丰富的数据结构实现方式。
对于学习数据结构的C语言版课程,课后习题是巩固理论知识和提高实践能力的重要手段。
数据结构C语言版课后习题答案1. 单链表的实现在C语言中,单链表是一种常见的线性数据结构。
它由一系列节点组成,每个节点包含数据部分和指向下一个节点的指针。
实现单链表的基本操作通常包括创建链表、插入节点、删除节点、遍历链表等。
答案:- 创建链表:定义一个链表结构体,然后使用动态内存分配为每个节点分配内存。
- 插入节点:根据插入位置,调整前后节点的指针,并将新节点插入到链表中。
- 删除节点:找到要删除的节点,调整其前后节点的指针,然后释放该节点的内存。
- 遍历链表:从头节点开始,使用指针遍历链表,直到达到链表尾部。
2. 二叉树的遍历二叉树是一种特殊的树形数据结构,其中每个节点最多有两个子节点。
二叉树的遍历是数据结构中的一个重要概念,常见的遍历方式有前序遍历、中序遍历、后序遍历和层序遍历。
答案:- 前序遍历:先访问根节点,然后递归遍历左子树,最后递归遍历右子树。
- 中序遍历:先递归遍历左子树,然后访问根节点,最后递归遍历右子树。
- 后序遍历:先递归遍历左子树,然后递归遍历右子树,最后访问根节点。
- 层序遍历:使用队列,按照从上到下,从左到右的顺序访问每个节点。
3. 哈希表的实现哈希表是一种通过哈希函数将键映射到表中一个位置来访问记录的数据结构。
它提供了快速的数据访问能力,但需要处理哈希冲突。
答案:- 哈希函数:设计一个哈希函数,将键映射到哈希表的索引。
- 哈希冲突:使用链地址法、开放地址法或双重哈希法等解决冲突。
- 插入操作:计算键的哈希值,将其插入到对应的哈希桶中。
- 删除操作:找到键对应的哈希桶,删除相应的键值对。
4. 图的表示和遍历图是一种复杂的非线性数据结构,由顶点(节点)和边组成。
数据结构(c语言版)课后习题答案完整版资料
第1 章绪论5.选择题:C CBDCA6.试分析下面各程序段的时间复杂度。
(1)O(1)(2)O(m*n)(3)O(n2)(4)O(log3n)O(n (5)因为x++ 共执行了n-1+n-2+⋯⋯+1= n(n-1)/2 ,所以执行时间为2)(6)O( n )第2 章线性表1.选择题babadbcabdcddac2.算法设计题(6)设计一个算法,通过一趟遍历在单链表中确定值最大的结点。
ElemType Max (LinkList L ){if(L->next==NULL) return NULL;pmax=L->next; // 假定第一个结点中数据具有最大值p=L->next->next;while(p != NULL ){// 如果下一个结点存在if(p->data > pmax->data) pmax=p;p=p->next;}return pmax->data;原表(7)设计一个算法,通过遍历一趟,将链表中所有结点的链接方向逆转,仍利用的存储空间。
void inverse(LinkList &L) {// 逆置带头结点的单链表Lp=L->next; L->next=NULL;while ( p) {q=p->next; // q 指向*p 的后继p->next=L->next;L->next=p; // *p 插入在头结点之后p = q;}}(10)已知长度为n 的线性表 A 采用顺序存储结构,请写一时间复杂度为O (n) 、空间复杂度为O (1) 的算法,该算法删除线性表中所有值为item 的数据元素。
[ 题目分析] 在顺序存储的线性表上删除元素,通常要涉及到一系列元素的移动(删第i 个元素,第i+1 至第n 个元素要依次前移)。
本题要求删除线性表中所有值为item 的数据元素,并未要求元素间的相对位置不变。
数据结构c 版课后习题解析
【解答】自然语言,程序设计语言,流程图,伪代码,伪代码
(7)在一般情况下,一个算法的时间复杂度是()的函数。
【解答】问题规模
(8)设待处理问题的规模为n,若一个算法的时间复杂度为一个常数,则表示成数量级的形式为(),若为2n*log25n+ 8n,则表示成数量级的形式为()。
1.知识结构图
本章的知识结构如图2-1所示,其中第二层的椭圆代表本章的学习主线。
2. 学习要点
本章虽然讨论的是线性表,但涉及的许多问题都具有一定的普遍性,因此,本章是本课程的重点之一,也是其它后续章节的重要基础。
对于本章的学习要从两条明线、一条暗线出发。两条明线是线性表的逻辑结构和存储结构,一条暗线是算法(即基本操作的实现)。注意线性表的ADT定义、顺序表类定义和单链表类定义三者之间的关系;注意在不同的存储结构下,相同操作的不同实现算法;注意对顺序表和链表从时间性能和空间性能等方面进行综合对比,在实际应用中能为线性表选择或设计合适的存储结构。
【分析】操作示意图如图2-9所示:
⑺一个具有n个结点的单链表,在指针p所指结点后插入一个新结点的时间复杂度为();在给定值为x的结点后插入一个新结点的时间复杂度为()。
【解答】Ο(1),Ο(n)
【分析】在p所指结点后插入一个新结点只需修改指针,所以时间复杂度为Ο(1);而在给定值为x的结点后插入一个新结点需要先查找值为x的结点,所以时间复杂度为Ο(n)。
(5)可以用()定义一个完整的数据结构。
A数据元素B数据对象C数据关系D抽象数据类型
【解答】D
【分析】抽象数据类型是一个数据结构以及定义在该结构上的一组操作的总称。
数据结构与算法分析课后习题答案
数据结构与算法分析课后习题答案第一章:基本概念一、题目:什么是数据结构与算法?数据结构是指数据在计算机中存储和组织的方式,如栈、队列、链表、树等;而算法是一系列解决问题的清晰规范的指令步骤。
数据结构和算法是计算机科学的核心内容。
二、题目:数据结构的分类有哪些?数据结构可以分为以下几类:1. 线性结构:包括线性表、栈、队列等,数据元素之间存在一对一的关系。
2. 树形结构:包括二叉树、AVL树、B树等,数据元素之间存在一对多的关系。
3. 图形结构:包括有向图、无向图等,数据元素之间存在多对多的关系。
4. 文件结构:包括顺序文件、索引文件等,是硬件和软件相结合的数据组织形式。
第二章:算法分析一、题目:什么是时间复杂度?时间复杂度是描述算法执行时间与问题规模之间的增长关系,通常用大O记法表示。
例如,O(n)表示算法的执行时间与问题规模n成正比,O(n^2)表示算法的执行时间与问题规模n的平方成正比。
二、题目:主定理是什么?主定理(Master Theorem)是用于估计分治算法时间复杂度的定理。
它的公式为:T(n) = a * T(n/b) + f(n)其中,a是子问题的个数,n/b是每个子问题的规模,f(n)表示将一个问题分解成子问题和合并子问题的所需时间。
根据主定理的不同情况,可以得到算法的时间复杂度的上界。
第三章:基本数据结构一、题目:什么是数组?数组是一种线性数据结构,它由一系列具有相同数据类型的元素组成,通过索引访问。
数组具有随机访问、连续存储等特点,但插入和删除元素的效率较低。
二、题目:栈和队列有什么区别?栈和队列都是线性数据结构,栈的特点是“先进后出”,即最后压入栈的元素最先弹出;而队列的特点是“先进先出”,即最先入队列的元素最先出队列。
第四章:高级数据结构一、题目:什么是二叉树?二叉树是一种特殊的树形结构,每个节点最多有两个子节点。
二叉树具有左子树、右子树的区分,常见的有完全二叉树、平衡二叉树等。
数据结构与算法分析C版答案
Data Structures and Algorithm 习题答案Preface ii1 Data Structures and Algorithms 12 Mathematical Preliminaries 53 Algorithm Analysis 174 Lists, Stacks, and Queues 235 Binary Trees 326 General Trees 407 Internal Sorting 468 File Processing and External Sorting 549Searching 5810 Indexing 6411 Graphs 6912 Lists and Arrays Revisited 7613 Advanced Tree Structures 82iii Contents14 Analysis Techniques 8815 Limits to Computation 94PrefaceContained herein are the solutions to all exercises from the textbook A Practical Introduction to Data Structures and Algorithm Analysis, 2nd edition.For most of the problems requiring an algorithm I have given actual code. Ina few cases I have presented pseudocode. Please be aware that the code presented in this manual has not actually been compiled and tested. While I believe the algorithmsto be essentially correct, there may be errors in syntax as well as semantics. Most importantly, these solutions provide a guide to the instructor as to the intendedanswer, rather than usable programs.1Data Structures and AlgorithmsInstructor’s note: Unlike the other chapters, many of the questions in this chapter are not really suitable for graded work. The questions are mainly intended to get students thinking about data structures issues.This question does not have a specific right answer, provided the student keeps to the spirit of the question. Students may have trouble with the concept of “operations.”This exercise asks the student to expand on their concept of an integer representation.A good answer is described by Project , where a singly-linkedlist is suggested. The most straightforward implementation stores each digitin its own list node, with digits stored in reverse order. Addition and multiplicationare implemented by what amounts to grade-school arithmetic. Foraddition, simply march down in parallel through the two lists representingthe operands, at each digit appending to a new list the appropriate partial sum and bringing forward a carry bit as necessary. For multiplication, combine the addition function with a new function that multiplies a single digitby an integer. Exponentiation can be done either by repeated multiplication (not really practical) or by the traditional Θ(log n)-time algorithm based on the binary representation of the exponent. Discovering this faster algorithm will be beyond the reach of most students, so should not be required.A sample ADT for character strings might look as follows (with the normal interpretation of the function names assumed).Chap. 1 Data Structures and AlgorithmsSomeIn C++, this is 1for s1<s2; 0 for s1=s2;int strcmp(String s1, String s2)One’s compliment stores the binary representation of positive numbers, and stores the binary representation of a negative number with the bits inverted. Two’s compliment is the same, except t hat a negative number has its bits inverted and then one is added (for reasons of efficiency in hardware implementation).This representation is the physical implementation of an ADTdefined by the normal arithmetic operations, declarations, and other support given by the programming language for integers.An ADT for two-dimensional arrays might look as follows.Matrix add(Matrix M1, Matrix M2);Matrix multiply(Matrix M1, Matrix M2);Matrix transpose(Matrix M1);void setvalue(Matrix M1, int row, int col, int val);int getvalue(Matrix M1, int row, int col);List getrow(Matrix M1, int row);One implementation for the sparse matrix is described in Section Another implementationis a hash table whose search key is a concatenation of the matrix coordinates.Every problem certainly does not have an algorithm. As discussed in Chapter 15,there are a number of reasons why this might be the case. Some problems don’t have a sufficiently clear definition. Some problems, such as the halting problem, are non-computable. For some problems, such as one typically studied by artificial intelligence researchers, we simply don’t know a solution.We must assume that by “algorithm” we mean something composed of steps areof a nature that they can be performed by a computer. If so, than any algorithm can be expressed in C++. In particular, if an algorithm can be expressed in any other computer programming language, then it can be expressed in C++, since all (sufficiently general) computer programming languages compute the same set of functions.The primitive operations are (1) adding new words to the dictionary and (2) searching the dictionary for a given word. Typically, dictionary access involves some sort of pre-processing of the word to arrive at the “root” of the word.A twenty page document (single spaced) is likely to contain about 20,000 words. A user may be willing to wait a few seconds between individual “hits” of mis-spelled words, or perhaps up to a minute for the whole document to be processed. This means that a check for an individual word can take about 10-20 ms. Users will typically insert individual words into the dictionary interactively, so this process cantake a couple of seconds. Thus, search must be much more efficient than insertion.The user should be able to find a city based on a variety of attributes (name, location,perhaps characteristics such as population size). The user should also be able to insertand delete cities. These are the fundamental operations of any database system: search, insertion and deletion.A reasonable database has a time constraint that will satisfy the patience of a typicaluser. For an insert, delete, or exact match query, a few seconds is satisfactory. If thedatabase is meant to support range queries and mass deletions, the entire operation may be allowed to take longer, perhaps on the order of a minute. However, the time spent to process individual cities within the range must be appropriately reduced. Inpractice, the data representation will need to be such that it accommodates efficient processing to meet these time constraints. In particular, it may be necessary to supportoperations that process range queries efficiently by processing all cities in the range as a batch, rather than as a series of operations on individual cities.Students at this level are likely already familiar with binary search. Thus, theyshould typically respond with sequential search and binary search. Binary search should be described as better since it typically needs to make fewer comparisons (and thus is likely to be much faster).The answer to this question is discussed in Chapter 8. Typical measures of cost will be number of comparisons and number of swaps. Tests should include running timings on sorted, reverse sorted, and random lists of various sizes.Chap. 1 Data Structures and AlgorithmsThe first part is easy with the hint, but the second part is rather difficult to do withouta stack.a) bool checkstring(string S) {int count = 0;for (int i=0; i<length(S); i++)if (S[i] == ’(’) count++;if (S[i] == ’)’) {if (count == 0) return FALSE;count--;}}if (count == 0) return TRUE;else return FALSE;}b) int checkstring(String Str) {Stack S;int count = 0;for (int i=0; i<length(S); i++)if (S[i] == ’(’)(i);if (S[i] == ’)’) {if ()) return i;();}}if ()) return -1;else return ();}Answers to this question are discussed in Section .This is somewhat different from writing sorting algorithms for a computer, since person’s “working space” is typically limited, as is their ability to physically manipulatethe pieces of paper. Nonetheless, many of the common sorting algorithms have their analogs to solutions for this problem. Most typical answers will be insertion sort, variations on mergesort, and variations on binsort.Answers to this question are discussed in Chapter 8.2Mathematical Preliminaries(a) Not reflexive if the set has any members. One could argue it is symmetric, antisymmetric, and transitive, since no element violate any ofthe rules.(b)Not reflexive (for any female). Not symmetric (consider a brother andsister). Not antisymmetric (consider two brothers). Transitive (for any3 brothers).(c)Not reflexive. Not symmetric, and is antisymmetric. Not transitive(only goes one level).(d)Not reflexive (for nearly all numbers). Symmetric since a+ b= b+ a,so not antisymmetric. Transitive, but vacuously so (there can be nodistinct a, b,and cwhere aRband bRc).(e)Reflexive. Symmetric, so not antisymmetric. Transitive (but sort of vacuous).(f)Reflexive – check all the cases. Since it is only true when x= y,itis technically symmetric and antisymmetric, but rather vacuous. Likewise,it is technically transitive, but vacuous.In general, prove that something is an equivalence relation by proving that it is reflexive, symmetric, and transitive.(a)This is an equivalence that effectively splits the integers into odd andeven sets. It is reflexive (x+ xis even for any integer x), symmetric(since x+ y= y+ x) and transitive (since you are always adding twoodd or even numbers for any satisfactory a, b,and c).(b)This is not an equivalence. To begin with, it is not reflexive for any integer.(c)This is an equivalence that divides the non-zero rational numbers into positive and negative. It is reflexive since x˙x>0. It is symmetric sincexy˙= yx˙. It is transitive since any two members of the given classsatisfy the relationship.5Chap. 2 Mathematical Preliminaries(d)This is not an equivalance relation since it is not symmetric. For example, a=1and b=2.(e)This is an eqivalance relation that divides the rationals based on their fractional values. It is reflexive since for all a,=0. It is symmetricsince if=xthen=.x. It is transitive since any two rationalswith the same fractional value will yeild an integer.(f)This is not an equivalance relation since it is not transitive. For example, 4.2=2and 2.0=2,but 4.0=4.A relation is a partial ordering if it is antisymmetric and transitive. (a)Not a partial ordering because it is not transitive.(b)Is a partial ordering bacause it is antisymmetric (if ais an ancestor ofb, then bcannot be an ancestor of a) and transitive (since the ancestorof an ancestor is an ancestor).(c)Is a partial ordering bacause it is antisymmetric (if ais older than b,then bcannot be older than a) and transitive (since if ais older than band bis older than c, ais older than c).(d)Not a partial ordering, since it is not antisymmetric for any pair of sisters.(e)Not a partial ordering because it is not antisymmetric.(f)This is a partial ordering. It is antisymmetric (no violations exist) and transitive (no violations exist).A total ordering can be viewed as a permuation of the elements. Since there are n!permuations of nelements, there must be n!total orderings.This proposed ADT is inspired by the list ADT of Chapter 4.void clear();void insert(int);void remove(int);void sizeof();bool isEmpty();bool isInSet(int);This proposed ADT is inspired by the list ADT of Chapter 4. Note that whileit is similiar to the operations proposed for Question , the behaviour is somewhat different.void clear();void insert(int);void remove(int);void sizeof();7bool isEmpty();long ifact(int n) {The iterative version requires careful examination to understand whatit does, or to have confidence that it works as claimed.(b)Fibr is so much slower than Fibi because Fibr re-computes thebulk of the series twice to get the two values to add. What is muchworse, the recursive calls to compute the subexpressions also re-computethe bulk of the series, and do so recursively. The result is an exponential explosion. In contrast, Fibicomputes each value in the seriesexactly once, and so its running time is proportional to n.void GenTOH(int n, POLE goal, POLE t1, POLE t2,POLE* curr) {if (curr[n] == goal) Put others on t1.GenTOH(n-1, t1, goal, t2, curr);move(t2, goal);GenTOH(n-1, goal, t1, t2, curr); In theory, this series approaches, but never reaches,0, so it will go on forever. In practice, the value should become computationally indistinguishable from zero, and terminate. However, this is terrible programming practice.Chap. 2 Mathematical Preliminariesvoid allpermute(int array[], int n, int currpos) {if (currpos == (n-1)} {printout(array);return;}for (int i=currpos; i<n; i++) {swap(array, currpos, i);allpermute(array, n, currpos+1);swap(array, currpos, i); The idea is the print out theelements at the indicated bit positions within the set. If we do this for values in the range 0 to 2n.1, we will get the entire powerset.void powerset(int n) {for (int i=0; i<ipow(2, n); i++) {for (int j=0; j<n; j++)if (bitposition(n, j) == 1) cout << j << " ";cout << endl;}Proof: Assume that there is a largest prime number. Call it Pn,the nthlargest prime number, and label all of the primes in order P1 =2, P2 =3,and so on. Now, consider the number Cformed by multiplying all of the nprime numbers together. The value C+1is not divisible by any of the nprime numbers. C+1is a prime number larger than Pn, a contradiction.Thus, we conclude that there is no largest prime number. .Note: This problem is harder than most sophomore level students can handle.√Proof: The proof is by contradiction. Assume that 2is rational. By definition, there exist integers pand qsuch that√p2=,qwhere pand qhave no common factors (that is, the fraction p/qis in lowestterms). By squaring both sides and doing some simple algebraic manipulation, we get2p2=2q222q= pSince p2 must be even, pmust be even. Thus,9222q=4(p)222q=2(p)2This implies that q2 is also even. Thus, pand qare both even, which contra√dicts the requirement that pand qhave no common factors. Thus, 2mustbe irrational. .The leftmost summation sums the integers from 1 to n. The second summation merely reverses this order, summing the numbers from n.1+1=ndown to n.n+1=1. The third summation has a variable substitution ofi, with a corresponding substitution in the summation bounds. Thus,it is also the summation of n.0=nto n.(n.1)=1.Proof:(a) Base case.For n=1, 12 = [2(1)3 +3(1)2 +1]/6=1. Thus, theformula is correct for the base case.(b) Induction Hypothesis.2(n.1)3 +3(n.1)2 +(n.1)i2 =.6i=1(c) Induction Step.i2 i2 +n2=i=1 i=12(n.1)3 +3(n.1)2 +(n.1)2=+n62n3 .6n2 +6n.2+3n2 .6n+3+n.1 2=+n62n3 +3n2 +n=.6Thus, the theorem is proved by mathematical induction. .Proof:(a) Base case.For n=1, 1/2=1.1/2=1/2. Thus, the formula iscorrect for the base case.(b) Induction Hypothesis.11=1..2i=1Chap. 2 Mathematical Preliminaries(c) Induction Step.1 11=+iin222i=1 i=111=1.+n221=1..n2Thus, the theorem is proved by mathematical induction. . Proof:(a) Base case. For n=0, 20 =21 .1=1. Thus, the formula is correctfor the base case.(b) Induction Hypothesis.2i=2n.1.i=0(c) Induction Step.2i=2i+2ni=0 i=0n=2n.1+2n+1 .1=2.Thus, the theorem is proved by mathematical induction. .The closed form solution is 3n+, which I deduced by noting that 3F (n).2n+1 .3F(n)=2F(n)=3. Now, to verify that this is correct, use mathematical induction as follows.For the base case, F(1)=3= .2The induction hypothesis is that =(3n.3)/2.i=1So,3i=3i+3ni=1 i=13n.3n= +32n+1 .33= .2Thus, the theorem is proved by mathematical induction.11nTheorem (2i)=n2 +n.i=1(a) Proof: We know from Example that the sum of the first noddnumbers is ith even number is simply one greater than the ithodd number. Since we are adding nsuch numbers, the sum must be n greater, or n2 +n. .(b) Proof: Base case: n=1yields 2=12 +1, which is true.Induction Hypothesis:2i=(n.1)2 +(n.1).i=1Induction Step: The sum of the first neven numbers is simply the sum of the first n.1even numbers plus the nth even number.2i=( 2i)+2ni=1 i=1=(n.1)2 +(n.1)+2n=(n2 .2n+1)+(n.1)+2n= n2 .n+2n= n2 +n.nThus, by mathematical induction, 2i=n2 +n. .i=1Proof:52Base case. For n=1,Fib(1) = 1 <n=2,Fib(2) = 1 <(5).3Thus, the formula is correct for the base case.Induction Hypothesis. For all positive integers i<n,5 iFib(i)<().3Induction Step. Fib(n)=Fib(n.1)+Fib(n.2)and, by the InductionHypothesis, Fib(n.1)<(5) and Fib(n.3355Fib(n) <() +()3355 5<() +()333Chap. 2 Mathematical Preliminaries85= ()3355<()2()33n5= .3Thus, the theorem is proved by mathematical induction. .Proof:12(1+1)23 =(a) Base case. For n=1, 1=1. Thus, the formula is correct4for the base case.(b) Induction Hypothesis.22(n.1)ni3 = .4i=0(c) Induction Step.n2(n.1)n2i33=+n4i=02n4 .2n3 +n3=+n4n4 +2n3 +n2=4n2(n2 +2n+2)=42n2(n+1)=4Thus, the theorem is proved by mathematical induction..(a) Proof: By contradiction. Assume that the theorem is false. Then, each pigeonhole contains at most 1 pigeon. Since there are nholes, there isroom for only npigeons. This contradicts the fact that a total of n+1pigeons are within the nholes. Thus, the theorem must be correct. .(b) Proof:i. Base case.For one pigeon hole and two pigeons, there must betwo pigeons in the hole.ii. Induction Hypothesis.For npigeons in n.1holes, some holemust contain at least two pigeons.13iii. Induction Step. Consider the case where n+1pigeons are in nholes. Eliminate one hole at random. If it contains one pigeon, eliminate it as well, and by the induction hypothesis some otherhole must contain at least two pigeons. If it contains no pigeons, then again by the induction hypothesis some other hole must contain at least two pigeons (with an extra pigeon yet to be placed). Ifit contains more than one pigeon, then it fits the requirements of the theorem directly..(a)When we add the nth line, we create nnew regions. But, we startwith one region even when there are no lines. Thus, the recurrence is F(n)=F(n.1)+n+1.(b) This is equivalent to the summation F(n)=1+ i=1 ni.(c) This is close to a summation we already know (equation .Base case: T(n.1)=1=1(1+1)/2.Induction hypothesis: T(n.1)=(n.1)(n)/2.Induction step:T(n)= T(n.1)+n=(n.1)(n)/2+n= n(n+1)/2.Thus, the theorem is proved by mathematical induction.If we expand the recurrence, we getT(n)=2T(n.1)+1=2(2T(n.2)+1)+1)=4T(n.2+2+1.Expanding again yieldsT(n)=8T(n.3)+4+2+1.From this, we can deduce a pattern and hypothesize that the recurrence is equivalent tonT(n)= .12i=2n.1.i=0To prove this formula is in fact the proper closed form solution, we use mathematical induction.Base case: T(1)=21 .1=1.14Chap. 2 Mathematical PreliminariesInduction hypothesis: T(n.1)= .1.Induction step:T(n)=2T(n.1)+1= 2 .1) + 1=2n.1.Thus, as proved by mathematical induction, this formula is indeed the correctclosed form solution for the recurrence.(a)The probability is for each choice.(b)The average number of “1” bits is n/2, since each position hasproba bility of being “1.”(c)The leftmost “1” will be the leftmost bit (call it position 0) with probability ; in position 1 with probability , and so on. The numberof positions we must examine is 1 in the case where the leftmost “1” isin position 0; 2 when it is in position 1, and so on. Thus, the expectedcost is the value of the summationni.2ii=1The closed form for this summation is 2 .n+2, or just less than two.2nThus, we expect to visit on average just less than two positions. (Studentsat this point will probably not be able to solve this summation,and it is not given in the book.)There are at least two ways to approach this problem. One is to estimate the volume directly. The second is to generate volume as a function of weight. This is especially easy if using the metric system, assuming that the human body is roughly the density of water. So a 50 Kilo person has a volumeslightly less than 50 liters; a 160 pound person has a volume slightly less than 20 gallons.(a) Image representations vary considerably, so the answer will vary as a result. One example answer is: Consider VGA standard size, full-color(24 bit) images, which is 3 ×640 ×480, or just less than 1 Mbyte perimage. The full database requires some 30-35 CDs.(b)Since we needed 30-35 CDs before, compressing by a factor of 10 isnot sufficient to get the database onto one CD.[Note that if the student picked a smaller format, such as estimating thesize of a “typical” gif image, the result might well fit onto a single CD.](I saw this problem in John Bentley’s Programming Pearls.) Approach 1:The model is Depth X Width X Flow where Depth and Width are in milesand Flow is in miles/day. The Mississippi river at its mouth is about 1/4 mile wide and 100 feet (1/50 mile) deep, with a flow of around 15 miles/hour =360 miles/day. Thus, the flow is about 2 cubic miles/day.Approach 2: What goes out must equal what goes in. The model is Area XRainfall where Area is in square miles and Rainfall is in (linear) miles/day. The Mississipi watershed is about 1000 X 1000 miles, and the average rainfalis about 40 inches/year ≈.1 inches/day ≈.000002 miles/day (2 X .Thus, the flow is about 2 cubic miles/day.Note that the student should NOT be providing answers that look like theywere done using a calculator. This is supposed to be an exercise in estimation! The amount of the mortgage is irrelevant, since this is a question about rates. However, to give some numbers to help you visualize the problem, pick a$100,000 mortgage. The up-front charge would be $1,000, and the savingswould be 1/4% each payment over the life of the mortgage. The monthlycharge will be on the remaining principle, being the highest at first and gradually reducing over time. But, that has little effect for the first few years.At the grossest approximation, you paid 1% to start and will save 1/4% each year, requiring 4 years. To be more precise, 8% of $100,000 is $8,000, while7 3/4% is $7,750 (for the first year), with a little less interest paid (and therefore saved) in following years. This will require a payback period of slightlyover 4 years to save $1000. If the money had been invested, then in 5 yearsthe investment would be worth about $1300 (at 5would be close to 5 1/2years.Disk drive seek time is somewhere around 10 milliseconds or a little lessin 2000. RAM memory requires around 50 nanoseconds – much less thana microsecond. Given that there are about 30 million seconds in a year, a machine capable of executing at 100 MIPS would execute about 3 billionbillion (3 .1018) instructions in a year.Typical books have around 500 pages/inch of thickness, so one million pages requires 2000 inches or 150-200 feet of bookshelf. This would be in excess of 50 typical shelves, or 10-20 bookshelves. It is within the realm of possibility that an individual home has this many books, but it is rather unusual.A typical page has around 400 words (best way to derive this is to estimatethe number of words/line and lines/page), and the book has around 500 pages,so the total is around 200,000 words.16Chap. 2 Mathematical PreliminariesAn hour has 3600 seconds, so one million seconds is a bit less than 300 hours.A good estimater will notice that 3600 is about 10% greater than 3333, so the actual number of hours is about 10% less than 300, or close to 270. (The real value is just under 278). Of course, this is just over 11 days.Well over 100,000, depending on what you wish to classify as a city or town. The real question is what technique the student uses.(a) The time required is 1 minute for the first mile, then 60/59 minutesfor the second mile, and so on until the last mile requires 60/1=60minutes. The result is the following summation.60 6060/i=60 1/i=60H60.i=1 i=1(b)This is actually quite easy. The man will never reach his destination,since his speed approaches zero as he approaches the end of the journey.3Algorithm AnalysisNote that nis a positive integer.5nlog nis most efficient for n=1.2nis most efficient when 2 ≤n≤4.10nis most efficient for all n>5. 20nand 2nare never moreefficient than the other choices.Both log3 nand log2 nwill have value 0 when n=1.Otherwise, 2 is the most efficient expression for all n>1.2/32 3n2 log3nlog2 nn20n4nn!.(a)n+6 inputs (an additive amount, independent of n).(b)8ninputs (a multiplicative factor).(c)64ninputs.100n.10n.√About (actually, 3 100n).n+6.(a)These questions are quite hard. If f(n)=2n= x, then f(2n)=22n=2(2n)2 = x.(b)The answer is 2(nlog2 3). Extending from part (a), we need some way tomake the growth rate even higher. In particular, we seek some way tolog2 3 =make the exponent go up by a factor of 3. Note that, if f(n)= n)=2log2 3log2 3 =3x y, then f(2nn. So, we combine this observationwith part (a) to get the desired answer.First, we need to find constants cand nosuch that 1 ≤c×1 for n>n0.This is true for any positive value c<1 and any positive value of n0 (since nplays no role in the equation).Next, we need to find constants cand n0 such that 1 ≤c×nfor n>n0.This is true for, say, c=1 and n0 =1.1718Chap. 3 Algorithm AnalysisOther values for n0 and care possible than what is given here.(a)The upper bound is O(n) for n0 >0 and c= c1. The lower bound isΩ(n) for n0 >0 and c= c1.(b)The upper bound is O(n3) for n0 >c3 and c= c2 +1. The lowerbound is Ω(n3) for n0 >c3 and c= c2.(c)The upper bound is O(nlog n) for n0 >c5 and c= c4 +1. The lowerbound is Ω(nlog n) for n0 >c5 and c= c4.(d)The upper bound is O(2n) for n0 >c7100 and c= c6 +lower bound is Ω(2n) for n0 >c7100 and c= c6. (100 is used forconvenience to insure that 2n>n6)(a) f(n)=Θ(g(n)) since log n2 = 2 log n.(b)f(n) is in Ω(g(n)) since ncgrows faster than log ncfor any c.(c)f(n) is in Ω(g(n)). Dividing both sides by log n, we see that log n grows faster than 1.(d)f(n) is in Ω(g(n)). If we take both f(n) and g(n) as exponents for 2,2we get 2non one side and 2log2 n=(2log n)2 = n2 on the other, and ngrows slower than 2n.(e)f(n) is in Ω(g(n)). Dividing both sides by log nand throwing awaythe low order terms, we see that ngrows faster than 1.(f)f(n)=Θ(g(n)) since log 10 and 10 are both constants.2(g)f(n) is in Ω(g(n)) since 2ngrows faster than 10n.(h)f(n) is in O(g(n)). 3n=, and if we divide both sides by 2n,we see thatgrows faster than 1.(a) This fragment is Θ(1).(b)This fragment is Θ(n) since the outer loop is executed a constant number。
严蔚敏《数据结构(c语言版)习题集》全答案
说明: 1.本文是对严蔚敏《数据结构(c语言版)习题集》一书中所有算法设计题目的解决方案,主要作者为计算机版版主一具.以下网友:siice,龙抬头,iamkent,zames,birdthinking等为答案的修订和完善工作提出了宝贵意见,在此表示感谢;2.本解答中的所有算法均采用类c语言描述,设计原则为面向交流、面向阅读,作者不保证程序能够上机正常运行(这种保证实际上也没有任何意义);3.本解答原则上只给出源代码以及必要的注释,对于一些难度较高或思路特殊的题目将给出简要的分析说明,对于作者无法解决的题目将给出必要的讨论.目前尚未解决的题目有: 5.20,10.40;4.请读者在自己已经解决了某个题目或进行了充分的思考之后,再参考本解答,以保证复习效果;5.由于作者水平所限,本解答中一定存在不少这样或者那样的错误和不足,希望读者们在阅读中多动脑、勤思考,争取发现和纠正这些错误,写出更好的算法来.请将你发现的错误或其它值得改进之处向作者报告:yi-ju@第一章绪论1.16void print_descending(int x,int y,int z)//按从大到小顺序输出三个数{scanf("%d,%d,%d",&x,&y,&z);if(x<y)x<->y;//<->为表示交换的双目运算符,以下同if(y<z)y<->z;if(x<y)x<->y;//冒泡排序printf("%d%d%d",x,y,z);}//print_descending1.17Status fib(int k,int m,int&f)//求k阶斐波那契序列的第m项的值f {int tempd;if(k<2||m<0)return ERROR;if(m<k-1)f=0;else if(m==k-1)f=1;else{for(i=0;i<=k-2;i++)temp[i]=0;temp[k-1]=1;//初始化for(i=k;i<=m;i++)//求出序列第k至第m个元素的值{sum=0;for(j=i-k;j<i;j++)sum+=temp[j];temp[i]=sum;}f=temp[m];}return OK;}//fib分析:通过保存已经计算出来的结果,此方法的时间复杂度仅为O(m^2).如果采用递归编程(大多数人都会首先想到递归方法),则时间复杂度将高达O(k^m).1.18typedef struct{char*sport;enum{male,female}gender;char schoolname;//校名为'A','B','C','D'或'E'char*result;int score;}resulttype;typedef struct{int malescore;int femalescore;int totalscore;}scoretype;void summary(resulttype result[])//求各校的男女总分和团体总分,假设结果已经储存在result[]数组中{scoretype score;i=0;while(result[i].sport!=NULL){switch(result[i].schoolname){case'A':score[0].totalscore+=result[i].score;if(result[i].gender==0)score[0].malescore+=result[i].score;else score[0].femalescore+=result[i].score;break;case'B':score.totalscore+=result[i].score;if(result[i].gender==0)score.malescore+=result[i].score;else score.femalescore+=result[i].score;break;………………}i++;}for(i=0;i<5;i++){printf("School%d:\n",i);printf("Total score of male:%d\n",score[i].malescore);printf("Total score of female:%d\n",score[i].femalescore);printf("Total score of all:%d\n\n",score[i].totalscore);}}//summary1.19Status algo119(int a[ARRSIZE])//求i!*2^i序列的值且不超过maxint {last=1;for(i=1;i<=ARRSIZE;i++){a[i-1]=last*2*i;if((a[i-1]/last)!=(2*i))reurn OVERFLOW;last=a[i-1];return OK;}}//algo119分析:当某一项的结果超过了maxint时,它除以前面一项的商会发生异常.1.20void polyvalue(){float ad;float*p=a;printf("Input number of terms:");scanf("%d",&n);printf("Input the%d coefficients from a0to a%d:\n",n,n);for(i=0;i<=n;i++)scanf("%f",p++);printf("Input value of x:");scanf("%f",&x);p=a;xp=1;sum=0;//xp用于存放x的i次方for(i=0;i<=n;i++){sum+=xp*(*p++);xp*=x;}printf("Value is:%f",sum);}//polyvalue第二章线性表2.10Status DeleteK(SqList&a,int i,int k)//删除线性表a中第i个元素起的k个元素{if(i<1||k<0||i+k-1>a.length)return INFEASIBLE;for(count=1;i+count-1<=a.length-k;count++)//注意循环结束的条件a.elem[i+count-1]=a.elem[i+count+k-1];a.length-=k;return OK;}//DeleteK2.11Status Insert_SqList(SqList&va,int x)//把x插入递增有序表va中{if(va.length+1>va.listsize)return ERROR;va.length++;for(i=va.length-1;va.elem[i]>x&&i>=0;i--)va.elem[i+1]=va.elem[i];va.elem[i+1]=x;return OK;}//Insert_SqList2.12int ListComp(SqList A,SqList B)//比较字符表A和B,并用返回值表示结果,值为正,表示A>B;值为负,表示A<B;值为零,表示A=B{for(i=1;A.elem[i]||B.elem[i];i++)if(A.elem[i]!=B.elem[i])return A.elem[i]-B.elem[i];return0;}//ListComp2.13LNode*Locate(LinkList L,int x)//链表上的元素查找,返回指针{for(p=l->next;p&&p->data!=x;p=p->next);return p;}//Locate2.14int Length(LinkList L)//求链表的长度{for(k=0,p=L;p->next;p=p->next,k++);return k;}//Length2.15void ListConcat(LinkList ha,LinkList hb,LinkList&hc)//把链表hb 接在ha后面形成链表hc{hc=ha;p=ha;while(p->next)p=p->next;p->next=hb;}//ListConcat2.16见书后答案.2.17Status Insert(LinkList&L,int i,int b)//在无头结点链表L的第i个元素之前插入元素b{p=L;q=(LinkList*)malloc(sizeof(LNode));q.data=b;if(i==1){q.next=p;L=q;//插入在链表头部}else{while(--i>1)p=p->next;q->next=p->next;p->next=q;//插入在第i个元素的位置}}//Insert2.18Status Delete(LinkList&L,int i)//在无头结点链表L中删除第i个元素{if(i==1)L=L->next;//删除第一个元素else{p=L;while(--i>1)p=p->next;p->next=p->next->next;//删除第i个元素}}//Delete2.19Status Delete_Between(Linklist&L,int mink,int maxk)//删除元素递增排列的链表L中值大于mink且小于maxk的所有元素{p=L;while(p->next->data<=mink)p=p->next;//p是最后一个不大于mink 的元素if(p->next)//如果还有比mink更大的元素{q=p->next;while(q->data<maxk)q=q->next;//q是第一个不小于maxk的元素p->next=q;}}//Delete_Between2.20Status Delete_Equal(Linklist&L)//删除元素递增排列的链表L中所有值相同的元素{p=L->next;q=p->next;//p,q指向相邻两元素while(p->next){if(p->data!=q->data){p=p->next;q=p->next;//当相邻两元素不相等时,p,q都向后推一步}else{while(q->data==p->data){free(q);q=q->next;}p->next=q;p=q;q=p->next;//当相邻元素相等时删除多余元素}//else}//while}//Delete_Equal2.21void reverse(SqList&A)//顺序表的就地逆置{for(i=1,j=A.length;i<j;i++,j--)A.elem[i]<->A.elem[j];}//reverse2.22void LinkList_reverse(Linklist&L)//链表的就地逆置;为简化算法,假设表长大于2{p=L->next;q=p->next;s=q->next;p->next=NULL;while(s->next){q->next=p;p=q;q=s;s=s->next;//把L的元素逐个插入新表表头}q->next=p;s->next=q;L->next=s;}//LinkList_reverse分析:本算法的思想是,逐个地把L的当前元素q插入新的链表头部,p为新表表头.2.23void merge1(LinkList&A,LinkList&B,LinkList&C)//把链表A和B合并为C,A和B的元素间隔排列,且使用原存储空间{p=A->next;q=B->next;C=A;while(p&&q){s=p->next;p->next=q;//将B的元素插入if(s){t=q->next;q->next=s;//如A非空,将A的元素插入}p=s;q=t;}//while}//merge12.24void reverse_merge(LinkList&A,LinkList&B,LinkList&C)//把元素递增排列的链表A和B合并为C,且C中元素递减排列,使用原空间{pa=A->next;pb=B->next;pre=NULL;//pa和pb分别指向A,B的当前元素while(pa||pb){if(pa->data<pb->data||!pb){pc=pa;q=pa->next;pa->next=pre;pa=q;//将A的元素插入新表}else{pc=pb;q=pb->next;pb->next=pre;pb=q;//将B的元素插入新表}pre=pc;}C=A;A->next=pc;//构造新表头}//reverse_merge分析:本算法的思想是,按从小到大的顺序依次把A和B的元素插入新表的头部pc处,最后处理A或B的剩余元素.2.25void SqList_Intersect(SqList A,SqList B,SqList&C)//求元素递增排列的线性表A和B的元素的交集并存入C中{i=1;j=1;k=0;while(A.elem[i]&&B.elem[j]){if(A.elem[i]<B.elem[j])i++;if(A.elem[i]>B.elem[j])j++;if(A.elem[i]==B.elem[j]){C.elem[++k]=A.elem[i];//当发现了一个在A,B中都存在的元素,i++;j++;//就添加到C中}}//while}//SqList_Intersect 2.26void LinkList_Intersect(LinkList A,LinkList B,LinkList&C)//在链表结构上重做上题{p=A->next;q=B->next;pc=(LNode*)malloc(sizeof(LNode));while(p&&q){if(p->data<q->data)p=p->next;else if(p->data>q->data)q=q->next;else{s=(LNode*)malloc(sizeof(LNode));s->data=p->data;pc->next=s;pc=s;p=p->next;q=q->next;}}//whileC=pc;}//LinkList_Intersect2.27void SqList_Intersect_True(SqList&A,SqList B)//求元素递增排列的线性表A和B的元素的交集并存回A中{i=1;j=1;k=0;while(A.elem[i]&&B.elem[j]){if(A.elem[i]<B.elem[j])i++;else if(A.elem[i]>B.elem[j])j++;else if(A.elem[i]!=A.elem[k]){A.elem[++k]=A.elem[i];//当发现了一个在A,B中都存在的元素i++;j++;//且C中没有,就添加到C中}}//whilewhile(A.elem[k]) A.elem[k++]=0;}//SqList_Intersect_True2.28void LinkList_Intersect_True(LinkList&A,LinkList B)//在链表结构上重做上题{p=A->next;q=B->next;pc=A;while(p&&q){if(p->data<q->data)p=p->next;else if(p->data>q->data)q=q->next;else if(p->data!=pc->data){pc=pc->next;pc->data=p->data;p=p->next;q=q->next;}}//while}//LinkList_Intersect_True2.29void SqList_Intersect_Delete(SqList&A,SqList B,SqList C){i=0;j=0;k=0;m=0;//i指示A中元素原来的位置,m为移动后的位置while(i<A.length&&j<B.length&&k<C.length){if(B.elem[j]<C.elem[k])j++;else if(B.elem[j]>C.elem[k])k++;else{same=B.elem[j];//找到了相同元素samewhile(B.elem[j]==same)j++;while(C.elem[k]==same)k++;//j,k后移到新的元素while(i<A.length&&A.elem[i]<same)A.elem[m++]=A.elem[i++];//需保留的元素移动到新位置while(i<A.length&&A.elem[i]==same)i++;//跳过相同的元素}}//whilewhile(i<A.length)A.elem[m++]=A.elem[i++];//A的剩余元素重新存储。
数据结构c语言课后习题答案
数据结构c语言课后习题答案数据结构C语言课后习题答案在学习数据结构和C语言的课程中,课后习题是非常重要的一部分。
通过做习题,我们可以巩固课堂上学到的知识,加深对数据结构和C语言的理解,并提高编程能力。
下面我们将分享一些数据结构C语言课后习题的答案,希望能够帮助大家更好地学习和掌握这门课程。
1. 题目:使用C语言实现一个栈的基本操作,包括入栈、出栈和获取栈顶元素。
答案:```c#include <stdio.h>#define MAX_SIZE 100typedef struct {int data[MAX_SIZE];int top;} Stack;void initStack(Stack *s) {s->top = -1;}void push(Stack *s, int value) {if (s->top == MAX_SIZE - 1) {printf("Stack is full\n");return;}s->data[++s->top] = value;}int pop(Stack *s) {if (s->top == -1) {printf("Stack is empty\n");return -1;}return s->data[s->top--];}int top(Stack *s) {if (s->top == -1) {printf("Stack is empty\n");return -1;}return s->data[s->top];}```2. 题目:使用C语言实现一个队列的基本操作,包括入队、出队和获取队首元素。
答案:```c#include <stdio.h>#define MAX_SIZE 100typedef struct {int data[MAX_SIZE];int front, rear;} Queue;void initQueue(Queue *q) {q->front = q->rear = 0;}void enqueue(Queue *q, int value) {if ((q->rear + 1) % MAX_SIZE == q->front) { printf("Queue is full\n");return;}q->data[q->rear] = value;q->rear = (q->rear + 1) % MAX_SIZE;}int dequeue(Queue *q) {if (q->front == q->rear) {printf("Queue is empty\n");return -1;}int value = q->data[q->front];q->front = (q->front + 1) % MAX_SIZE;return value;}int front(Queue *q) {if (q->front == q->rear) {printf("Queue is empty\n");return -1;}return q->data[q->front];}```通过以上两个例子,我们可以看到在C语言中实现栈和队列的基本操作并不复杂。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第3章栈和队列一、基础知识题3.1有五个数依次进栈:1,2,3,4,5。
在各种出栈的序列中,以3,4先出的序列有哪几个。
(3在4之前出栈)。
【解答】34215 ,34251, 345213.2铁路进行列车调度时,常把站台设计成栈式结构,若进站的六辆列车顺序为:1,2,3,4,5,6,那么是否能够得到435612, 325641, 154623和135426的出站序列,如果不能,说明为什么不能;如果能,说明如何得到(即写出"进栈"或"出栈"的序列)。
【解答】输入序列为123456,不能得出435612和154623。
不能得到435612的理由是,输出序列最后两元素是12,前面4个元素(4356)得到后,栈中元素剩12,且2在栈顶,不可能让栈底元素1在栈顶元素2之前出栈。
不能得到154623的理由类似,当栈中元素只剩23,且3在栈顶,2不可能先于3出栈。
得到325641的过程如下:1 2 3顺序入栈,32出栈,得到部分输出序列32;然后45入栈,5出栈,部分输出序列变为325;接着6入栈并退栈,部分输出序列变为3256;最后41退栈,得最终结果325641。
得到135426的过程如下:1入栈并出栈,得到部分输出序列1;然后2和3入栈,3出栈,部分输出序列变为13;接着4和5入栈,5,4和2依次出栈,部分输出序列变为13542;最后6入栈并退栈,得最终结果135426。
3.3若用一个大小为6的数组来实现循环队列,且当前rear和front的值分别为0和3,当从队列中删除一个元素,再加入两个元素后,rear和front的值分别为多少?【解答】2和 43.4设栈S和队列Q的初始状态为空,元素e1,e2,e3,e4,e5和e6依次通过栈S,一个元素出栈后即进队列Q,若6个元素出队的序列是e3,e5,e4,e6,e2,e1,则栈S的容量至少应该是多少?【解答】 43.5循环队列的优点是什么,如何判断“空”和“满”。
【解答】循环队列解决了常规用0--m-1的数组表示队列时出现的“假溢出”(即队列未满但不能入队)。
在循环队列中我们仍用队头指针等于队尾指针表示队空,而用牺牲一个单元的办法表示队满,即当队尾指针加1(求模)等于队头指针时,表示队列满。
也有通过设标记以及用一个队头或队尾指针加上队中元素个数来区分队列的“空”和“满”的。
3.6设长度为n的链队列用单循环链表表示,若只设头指针,则入队和出队的时间如何?若只设尾指针呢?【解答】若只设头指针,则入队的时间为O(n),出队的时间为O(1)。
若只设尾指针,则入队和出队的时间均为O(1)。
3.7指出下面程序段的功能是什么?(1)void demo1(SeqStack S){int i,arr[64],n=0;while(!StackEmpty(S)) arr[n++]=Pop(S);for(i=0;i<n;i++) Push(S,arr[i]);}【解答】程序段的功能是实现了栈中元素的逆置。
(2)void demo2(SeqStack S,int m)∥设栈中元素类型为int型{int x;SeqStack T;StackInit(T);while(!StackEmpty(S))if((x=Pop(S)!=m) Push(T,x);while(!(StackEmpty(T)) {x=Pop(T); Push(S,x);}}【解答】程序段的功能是删除了栈中值为m的元素。
(3)void demo3(SeQueue Q,int m)∥设队列中元素类型为int型{int x;SeqStack S;StackInit(S);while(!QueueEmpty(Q)){x=QueueOut(Q); Push(S,x);}while(!StackEmpty(S)){x=Pop(s); QueueIn(Q,x);}}【解答】程序段的功能是实现了队列中元素的逆置。
3.8试将下列递推过程改写为递归过程。
void ditui(int n){i=n;while(i>1) printf(i--);}【解答】void digui(int n){if(n>1){printf(n);digui(n-1);}}3.9写出下列中缀表达式的后缀表达式:(1)A*B*C (2)(A+B)*C-D (3)A*B+C/(D-E) (4)(A+B)*D+E/(F+A*D)+C 【解答】(1)ABC**(2)AB+C*D-(3)AB*CDE-/+(4)AB+D*EFAD*+/+C+3.10选择题:循环队列存储在数组A[0..m]中,则入队时的操作为( )。
A. rear=rear+1B. rear=(rear+1) % (m-1)C. rear=(rear+1) % mD. rear=(rear+1) % (m+1)【解答】D3.11 选择题:4个园盘的Hahoi塔,总的移动次数为( )。
A.7B. 8C.15D.16【解答】C3.12选择题:允许对队列进行的操作有( )。
A. 对队列中的元素排序B. 取出最近进队的元素C. 在队头元素之前插入元素D. 删除队头元素【解答】D二、算法设计题3.13 利用栈的基本操作,编写求栈中元素个数的算法。
【题目分析】将栈值元素出栈,出栈时计数,直至栈空。
【算法】int StackLength(Stack S){//求栈中元素个数int n=0;while(!StackEmpty(S){n++; Pop(S);}return n;}算法讨论:若要求统计完元素个数后,不能破坏原来栈,则在计数时,将原栈导入另一临时栈,计数完毕,再将临时栈倒入原栈中。
int StackLength(Stack S){//求栈中元素个数int n=0;Stack T;StackInit(T); //初始化临时栈Twhile(!StackEmpty(S){n++; Push(T,Pop(S));}while(!StackEmpty(T){Push(S,Pop(T));}return n;}3.14 双向栈S是在一个数组空间V[m]实现的两个栈,栈底分别处于数组空间的两端。
试为此双向栈设计栈初始化Init(S)、入栈Push(S,i,x)、出栈Pop(S,i)算法,其中i为0或1,用以指示栈号。
[题目分析]两栈共享向量空间,将两栈栈底设在向量两端,初始时,s1栈顶指针为-1,s2栈顶为m。
两栈顶指针相邻时为栈满。
两栈顶相向、迎面增长,栈顶指针指向栈顶元素。
#define ElemType int ∥假设元素类型为整型typedef struct{ElemType V[m]; ∥栈空间int top[2]; ∥top为两个栈顶指针}stk;stk S; ∥S是如上定义的结构类型变量,为全局变量(1)栈初始化int Init(){S.top[0]=-1;S.top[1]=m;return 1; //初始化成功}(2)入栈操作:int push(stk S ,int i,int x)∥i为栈号,i=0表示左栈,i=1为右栈,x是入栈元素。
入栈成功返回1,否则返回0{if(i<0||i>1){printf(“栈号输入不对\n”);exit(0);}if(S.top[1]-S.top[0]==1) {printf(“栈已满\n”);return(0);}switch(i){case 0: S.V[++S.top[0]]=x; return(1); break;case 1: S.V[--S.top[1]]=x; return(1);}}∥push(3)退栈操作ElemType pop(stk S,int i)∥退栈。
i代表栈号,i=0时为左栈,i=1时为右栈。
退栈成功返回退栈元素∥否则返回-1{if(i<0 || i>1){printf(“栈号输入错误\n”);exit(0);}switch(i){case0: if(S.top[0]==-1) {printf(“栈空\n”);return(-1);}else return(S.V[S.top[0]--]);case 1: if(S.top[1]==m {printf(“栈空\n”); return(-1);}else return(S.V[S.top[1]++]);}∥switch }∥算法结束(4)判断栈空int Empty();{return (S.top[0]==-1 && S.top[1]==m);}[算法讨论]请注意算法中两栈入栈和退栈时的栈顶指针的计算。
s1(左栈)是通常意义下的栈,而s2(右栈)入栈操作时,其栈顶指针左移(减1),退栈时,栈顶指针右移(加1)。
3.15设以数组Q[m]存放循环队列中的元素,同时设置一个标志tag,以tag=0和tag=1来区别在队头指针(front)和队尾指针(rear)相等时,队列状态为“空”还是“不空”。
试编写相应的入队(QueueIn)和出队(QueueOut)算法。
(1)初始化SeQueue QueueInit(SeQueue Q){//初始化队列Q.front=Q.rear=0; Q.tag=0;return Q;}(2)入队SeQueue QueueIn(SeQueue Q,int e){//入队列if((Q.tag==1) && (Q.rear==Q.front)) printf("队列已满\n");else {Q.rear=(Q.rear+1) % m;Q.data[Q.rear]=e;if(Q.tag==0) Q.tag=1; //队列已不空}return Q;}(3)出队ElemType QueueOut(SeQueue Q){//出队列if(Q.tag==0) printf("队列为空\n");else{Q.front=(Q.front+1) % m;e=Q.data[Q.front];if(Q.front==Q.rear) Q.tag=0; //空队列}return(e);}3.16假设用变量rear和length分别指示循环队列中队尾元素的位置和含元素的个数。
试给出此循环队列的定义,并写出相应的入队(QueueIn)和出队(QueueOut)算法。
【算法设计】(1)循环队列的定义typedef struct{ElemType Q[m]; ∥循环队列占m个存储单元int rear,length; ∥ rear指向队尾元素,length为元素个数}SeQueue;(2) 初始化SeQueue QueueInit (SeQueue cq)∥cq为循环队列,本算法进行队列初始化{ cq.rear=0; cq.length=0; return cq;}(3) 入队SeQueue QueueIn(SeQueue cq,ElemType x)∥cq是以如上定义的循环队列,本算法将元素x入队{if(cq.length==m) return(0); ∥队满else {cq.rear=(cq.rear+1) % m; ∥计算插入元素位置cq.Q[cq.rear]=x; ∥将元素x入队列cq.length++; ∥修改队列长度}return (cq);}(4)出队ElemType QueueOut(SeQueue cq)∥ cq是以如上定义的循环队列,本算法是出队算法,且返回出队元素{if(cq.length==0) return(0); ∥队空else { int front=(cq.rear-cq.length + 1) % m;∥出队元素位置cq.length--; ∥修改队列长度 return (cq.Q[front]); ∥返回对头元素}}3.17已知Ackerman函数定义如下:Akm(m,n)=试写出递归和非递归算法。