ch2部分习题解答
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
补充作业1:创建单链表(从表头->表尾)
int ListCreate(SLNode **la, int n) /*从键盘输入n个数,建立以la为头指针的带头结点的单链表*/ { int i; SLNode *p, *q; if (((*la)=(SLNode*)malloc(sizeof(SLNode)))==NULL) { printf(“内存空间不足!\n”); return 0; } q=*la; for (i=0; i<n; i++) { if((p=(SLNode*)malloc(sizeof(SLNode)))==NULL) { printf(“内存空间不足!\n”); return 0; } scanf("%d",&p->data); q->next=p; q=p; /*新结点p插入在表尾*/ } q->next=NULL; return 1; }
Chapter 2 线性表
练习:找出以下算法中的错误和低效之处,并将它改写为一个
既正确又高效的算法。 int Deletek(SeqList *L, int i, int k) /*从顺序表L中删除第i个元素起的k个元素*/ { int count,j; if (i<0||k<0||i+k>L->size) { printf(“\n参数不合法!”); return 0; } else { for (count=1;count<k;count++) { /*删除一个元素*/ for(j=L->size;j>=i+1;j--) L->list[j-1]=L->list[j]; L->size--; } return 1; } }
/*删除冗余结点*/
pa=(*lc)->next; while(pa) { pb=pa->next; while(pb&&pb->data==pa->data) { pc=pb; pb=pb->next; free(pc); } pa->next=pb; pa=pb; } }
书P46. 2-21(判断两个集合是否存在包含关系)
2009考研题:已知一个带头结点的单链表,假设该链表只给
出了头指针,在不改变链表的前提下,请设计一个尽可能高效 的算法,查找链表中倒数第k个结点(k为正整数),若查找成 功,算法输出该结点的data域的值,并返回1,否则,只返回0。
int Locatek(SLNode *h, int k) { SLNode *p,*q; int count; p=q=h->next; count=0; while (p!=NULL) { /* 先移动k次p指针,然后再同时移动p、q指针,直至p指针为空*/ p=p->next; if (count<k) count++; else q=q->next; } if (count<k) return 0; /* k值超过表长,查找失败*/ else { printf(“%d”,q->data); return 1; } }
(3)算法复杂性 算法的时间复杂度为O(n),空间复杂度为O(1)。
书P46. 2-19
void ListDeleteMore(SLNode *L, DataType x)
/*在带头结点的单链表中删除所有值为x的数据元素*/
{ SLNode *p,*s; p=L; while(p->next!=NULL) { s=p->next; if (s->data==x) { p->next=s->next; free(s); } else p=s; } }
补充作业2:
已知一个带头结点的循环双向链表,从第二个结点 至表尾递增有序。编写一个算法,将第一个结点删除并 插入表中适当位置,使整个链表递增有序。
void ListDIDL(DLNode *h) { DLNode *p,*s; p=h->next; if (p!=h) { h->next=p->next; p->next->prior=h;} /*删除链表中的第一个结点, else return; 并用p指针保存*/ s=h->next; while(s!=h&&p->data>s->data) s=s->next; /*查找p结点的插入位置*/ p->prior=s->prior; s->prior->next=p; p->next=s; s->prior=p; /*p结点插入在s结点之前*/ }
改进:int Deletek(SeqList *L, int i, int k) /*从顺序表L中删除第i个元素起的k个元素*/ { int count,j; if (i<0||k<=0||i+k>L->size) { printf(“\n参数不合法!”); return 0; } else { /*删除k个元素*/ for(j=i+k;j<L->size;j++) L->list[j-k]=L->list[j]; L->size-=k; return 1; } }
int ListSetInclude(SLNode *L1, SLNode *L2)
/*判断带头结点的单链表L1中的数据元素是否都是单链表L2 中的数据元素*/
{ SLNode *p1,*p2; p1=L1->next; while(p1!=NULL) { p2=L2->next; while(p2!=NULL&& p2->data!=p1->data) p2=p2->next; if(p2==NULL) return 0; p1=p1->next; } return 1; }
2010考研题:
设将n(n>1)个整数存放到一维数组R中。试设计一个在 时间和空间两方面尽可能高效的算法,将R中的序列循环左 移P(0<P<n)个位置,即将R中的数据由(x0,x1,…,xn-1)变 换为(xp,xp+1,…,xn-1,x0,x1,…,xp-1)。 (1)算法设计思想 先将n个数(x0,x1,…,xp,…,xn-1)原地逆置,得到 (xn-1,…,xp,xp-1,… x0),然后再将前n-p个和后p个元素分 别原地逆置,得到最终结果:xp,xp+1,…,xn-1,x0,x1,…,xp-1。 算法可以用两个函数实现。一个是逆置函数reverse(), 它将给定的数据逆置。另一个是循环左移函数leftShift(), 它调用reverse()函数三次,实现相应功能。
(2)算法实现
void reverse(int r[], int left, int right) { int i=left, j=right, temp; /*i等于左边界left,j等于右边界right*/ while(i<j) { /*交换r[i]与r[j]*/ temp=r[i]; r[i]=r[j]; r[j]=temp; i++; /*i右移一个位置*/ j--; /*j 左移一个位置*/ } }
/*删除值为x的结点*/
补充:已知一个带头结点的递增有序单链表L,试编写一高效 算法:删除该链表中所有元素值大于x且小于y的结点。
补充:
已知两个带表头结点的非递减有序单链表,头指针分别 为la和lb,试编写算法,先将两个表合并为一个带表头结点 的非递减有序单链表,然后删除表中结点值(data值)相同 的冗余结点,最后返回新单链表的头指针。 要求新单链表利用原来两个链表的结点空间,不另外生 成新结点。
void ListMergeDelete(SLNode *la, SLNode *lb, SLNode **lc) { SLNode *pa,*pb,*pc;
/*归并源自文库个有序表*/
(*lc)=la; pa=la->next; pb=lb->next; pc=la; while(pa&&pb) if (pa->data<=pb->data) { pc->next=pa; pc=pa; pa=pa->next; } else { pc->next=pb; pc=pb; pb=pb->next; } if(pa) pc->next=pa; else pc->next=pb; free(lb);
void leftShift(int r[], int n, int p) { if ( p>0 && p<n) { reverse(r,0,n-1); /*将全部数据逆置*/ reverse(r,0,n-p-1); /*将前n-p个元素逆置*/ reverse(r,n-p,n-1); /*将后p个元素逆置*/ } }