赞
踩
设n为正整数,试确定下列各程序中前置以记号@的语句的频度和算法复杂度。
(1) i=1; k=0;
while( i <= n-1)
{ k+=10*i; @ n-1
i++;
}
分析:T(n)=O(n)
(2) i=1; k=0;
do
{ k+=10*i; @ n-1
i++;
}while((i<=n-1);
分析:T(n)=O(n)
(3) i=1; k=0;
while(i<=n-1)
{ i++;
k+=10*i; @ n-1
}
分析:T(n)=O(n)
(4) k=0;
for(i=1; i<=n; i++){
for(j=i; j<=n; j++)
k++; @ n(n+1)/2
}
分析:
T
(
n
)
=
O
(
n
2
)
T(n)= O(n^2)
T(n)=O(n2)
(5) for(i=1; i<=n; i++)
{
for(j=1;j<=i; j++)
{
for(k=1; k<=j; k++)
X += delta; @ n(n+1)(n+2)/6
}
}
分析:
T
(
n
)
=
O
(
n
3
)
T(n)=O(n^3)
T(n)=O(n3)
(6) i=1; j=0;
while( i+j <= n)
{
if(i>j) @ n
j++;
else
i++;
}
分析:
通过分析以上程序段,可将i+j看成一个控制循环次数的变量,且每执行一次循环,i+j的值加1。该程序段的主要时间消耗是while循环,而while循环共做了n次,所以该程序段的执行时间为:T(n)=O(n)
(1) 在顺序表中插入或删除一个元素,需要平均移动 元素,具体移动的元素个数与 有关。
(2) 顺序表中逻辑上相邻的元素的物理位置 紧邻。单链表中逻辑上相邻的元素的物理位置 紧邻。
(3) 在单链表中,除了首元结点外,任一结点的存储位置由 指示。
(4) 在单链表中设置头结点的作用是 。
1、在顺序表中插入或删除一个元素,需要平均移动(表中一半)元素,具体移动的元素个数与(表长和该元素在表中的位置)有关。
2、顺序表中逻辑上相邻的元素的物理位置(必定)相邻。单链表中逻辑上相邻的元素的物理位置(不一定)相邻。
3、在单链表中,除了首元结点外,任一结点的存储位置由(其直接前驱结点的链域的值)指示。
4、在单链表中设置头结点的作用是(插入和删除元素不必进行特殊处理)。
答:在实际应用中,应根据具体问题的要求和性质来选择顺序表或链表作为线性表的存储结构,通常有以下几方面的考虑:
1.基于空间的考虑。当要求存储的线性表长度变化不大,易于事先确定其大小时,为了节约存储空间,宜采用顺序表;反之,当线性表长度变化大,难以估计其存储规模时,采用动态链表作为存储结构为好。
2.基于时间的考虑。若线性表的操作主要是进行查找,很少做插入和删除操作时,采用顺序表做存储结构为宜;反之, 若需要对线性表进行频繁地插入或删除等的操作时,宜采用链表做存储结构。并且,若链表的插入和删除主要发生在表的首尾两端,则采用尾指针表示的单循环链表为宜。
a. 删除P结点的直接后继结点的语句序列是____________________。
b. 删除P结点的直接前驱结点的语句序列是____________________。
c. 删除P结点的语句序列是____________________。
d. 删除首元结点的语句序列是____________________。
e. 删除尾元结点的语句序列是____________________。
(1) P=P->next;
(2) P->next=P;
(3) P->next=P->next->next;
(4) P=P->next->next;
(5) while(P!=NULL) P=P->next;
(6) while(Q->next!=NULL) { P=Q; Q=Q->next; }
(7) while(P->next!=Q) P=P->next;
(8) while(P->next->next!=Q) P=P->next;
(9) while(P->next->next!=NULL) P=P->next;
(10) Q=P;
(11) Q=P->next;
(12) P=L;
(13) L=L->next;
(14) free(Q);
解:a. (11) (3) (14)
b. (10) (12) (8) (3) (14)
c. (10) (12) (7) (3) (14)
d. (12) (11) (3) (14)
e. (9) (11) (3) (14)
a. 在P结点后插入S结点的语句序列是_______________________。
b. 在P结点前插入S结点的语句序列是_______________________。
c. 删除P结点的直接后继结点的语句序列是_______________________。
d. 删除P结点的直接前驱结点的语句序列是_______________________。
e. 删除P结点的语句序列是_______________________。
(1) P->next=P->next->next;
(2) P->priou=P->priou->priou;
(3) P->next=S;
(4) P->priou=S;
(5) S->next=P;
(6) S->priou=P;
(7) S->next=P->next;
(8) S->priou=P->priou;
(9) P->priou->next=P->next;
(10) P->priou->next=P;
(11) P->next->priou=P;
(12) P->next->priou=S;
(13) P->priou->next=S;
(14) P->next->priou=P->priou;
(15) Q=P->next;
(16) Q=P->priou;
(17) free§;
(18) free(Q);
解:a. (7) (6) (12)(3) (12和3的位置不能反,反了就错了)
b. (8) (5) (13)(4)
c. (15) (1) (11) (18)
d. (16) (2) (10) (18)
e. (14) (9) (17)
解:
Status InsertOrderList(SqList &va,ElemType x)
{
//在非递减的顺序表va中插入元素x并使其仍成为顺序表的算法
int i;
if(va.length==va.listsize)return(OVERFLOW);
for(i=va.length;i>0,x<va.elem[i-1];i--)
va.elem[i]=va.elem[i-1];
va.elem[i]=x;
va.length++;
return OK;
}
其他写法:
答:因已知顺序表L是递增有序表,所以只要从顺序表终端结点(设为i位置元素)开始向前寻找到第一个小于或等于x的元素位置i后插入该位置即可。
在寻找过程中,由于大于x的元素都应放在x之后,所以可边寻找,边后移元素,当找到第一个小于或等于x的元素位置i时,该位置也空出来了。
算法如下:
//顺序表存储结构如题2.7
void InsertIncreaseList( Seqlist *L , Datatype x )
{
int i;
if ( L->length>=ListSize)
Error(“overflow");
for ( i=L -> length ; i>0 && L->data[ i-1 ] > x ; i--)
L->data[ i ]=L->data[ i-1 ] ; // 比较并移动元素
L->data[ i ] =x;
L -> length++;
}
解:
// 顺序表的逆置
Status ListOppose_Sq(SqList &L)
{
int i;
ElemType x;
for(i=0;i<L.length/2;i++){
x=L.elem[i];
L.elem[i]=L.elem[L.length-1-i];
L.elem[L.length-1-i]=x;
}
return OK;
}
其他写法:
答:
要将该表逆置,可以将表中的开始结点与终端结点互换,第二个结点与倒数第二个结点互换,如此反复,就可将整个表逆置了。算法如下:
// 顺序表结构定义同上题
void ReverseList( Seqlist *L)
{
DataType temp ; //设置临时空间用于存放data
int i;
for (i=0;i<L->length/2;i++)//L->length/2为整除运算
{ temp = L->data[i]; //交换数据
L -> data[ i ] = L -> data[ L -> length-1-i];
L -> data[ L -> length - 1 - i ] = temp;
}
}
解:
// 将合并逆置后的结果放在C表中,并删除B表 Status ListMergeOppose_L(LinkList &A,LinkList &B,LinkList &C) { LinkList pa,pb,qa,qb; pa=A; pb=B; qa=pa; // 保存pa的前驱指针 qb=pb; // 保存pb的前驱指针 pa=pa->next; pb=pb->next; A->next=NULL; C=A; while(pa&&pb){ if(pa->data<pb->data){ qa=pa; pa=pa->next; qa->next=A->next; //将当前最小结点插入A表表头 A->next=qa; } else{ qb=pb; pb=pb->next; qb->next=A->next; //将当前最小结点插入A表表头 A->next=qb; } } while(pa){ qa=pa; pa=pa->next; qa->next=A->next; A->next=qa; } while(pb){ qb=pb; pb=pb->next; qb->next=A->next; A->next=qb; } pb=B; free(pb); return OK; }
其他写法:
解:
void 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的剩余元素.
解:
// 在单循环链表S中删除S的前驱结点
Status ListDelete_CL(LinkList &S)
{
LinkList p,q;
if(S==S->next)return ERROR;
q=S;
p=S->next;
while(p->next!=S){
q=p;
p=p->next;
}
q->next=p->next;
free(p);
return OK;
}
其他写法:
解:
已知指向这个结点的指针是s,那么要删除这个结点的直接前趋结点,就只要找到一个结点,它的指针域是指向s的直接前趋,然后用后删结点法,将结点*s的直接前趋结点删除即可。
算法如下:
void DeleteNode( ListNode *s)
{//删除单循环链表中指定结点的直接前趋结点
ListNode *p, *q;
p=s;
while( p->next->next!=s)
p=p->next;
//删除结点
q=p->next;
p->next=q->next;
free(p); //释放空间
}
注意:
若单循环链表的长度等于1,则只要把表删空即可。
解:
// 建立一个空的循环链表 Status InitList_DL(DuLinkList &L) { L=(DuLinkList)malloc(sizeof(DuLNode)); if(!L) exit(OVERFLOW); L->pre=NULL; L->next=L; return OK; } // 向循环链表中插入一个结点 Status ListInsert_DL(DuLinkList &L,ElemType e) { DuLinkList p; p=(DuLinkList)malloc(sizeof(DuLNode)); if(!p) return ERROR; p->data=e; p->next=L->next; L->next=p; return OK; } // 将单循环链表改成双向链表 Status ListCirToDu(DuLinkList &L) { DuLinkList p,q; q=L; p=L->next; while(p!=L){ p->pre=q; q=p; p=p->next; } if(p==L) p->pre=q; return OK; } 其他写法: Status DuLNode_Pre(DuLinkList &L)//完成双向循环链表结点的pre域 { for(p=L;!p->next->pre;p=p->next) p->next->pre=p; return OK; }//DuLNode_Pre
解:线性表是具有相同特性的数据元素的一个有限序列。栈是限定仅在表尾进行插入或删除操作的线性表。
void main()
{
Stack S;
char x,y;
InitStack(S);
x= ‘c’; y= ‘k’;
Push(S,x); Push(S, ‘a’); Push(S,y);
Pop(S,x); Push(S, ‘t’); Push(S,x);
Pop(S,x); Push(S, ‘s’);
while(!StackEmpty(S)) { Pop(S,y); printf(y); }
printf(x);
}
解:stack
void main( ){
Stack S;
Char x,y;
InitStack(S);
x=’c’;y=’k’; //x=‘c’, y=‘k’
Push(S,x); //x=‘c’,y=‘k’,S=“c”
Push(S,’a’); //x=‘c’,y=‘k’,S=“ac”
Push(S,y); //x=‘c’, y=‘k’, S=“kac”
Pop(S,x); //x=‘k’,y=‘k’,S=“ac”
Push(S,’t’); //x=‘k’,y=‘k’,S=“tac”
Push(S,x); //x=‘k’,y=‘k’,S=“ktac”
Pop(S,x); //x=‘k’,y=‘k’ S=“tac”
Push(S,’s’); //x=‘k’,y=‘k’ S=“stac”
while(!StackEmpty(S))
{
Pop(S,y); //依次为y=‘s’,y=‘t’,y=‘a’,y=‘c’
printf(y); //打印依次为s,t,a,c
}
Printf(x);//x=‘k’
}
所以最后应该是stack
void main() { Queue Q; InitQueue(Q); char x= ‘e’, y= ‘c’; EnQueue(Q, ‘h’); EnQueue(Q, ‘r’); EnQueue(Q, y); DeQueue(Q, x); EnQueue(Q, x); DeQueue(Q, x); EnQueue(Q, ‘a’); While(!QueueEmpty(Q)) { DeQueue(Q,y); cout<<y; } cout<<x; }
解:char
解:
typedef int ElemType; typedef struct NodeType{ ElemType data; NodeType *next; }QNode,*QPtr; typedef struct{ QPtr rear; int size; }Queue; Status InitQueue(Queue& q) { q.rear=NULL; q.size=0; return OK; } Status EnQueue(Queue& q,ElemType e) { QPtr p; p=new QNode; if(!p) return FALSE; p->data=e; if(!q.rear){ q.rear=p; p->next=q.rear; } else{ p->next=q.rear->next; q.rear->next=p; q.rear=p; } q.size++; return OK; } Status DeQueue(Queue& q,ElemType& e) { QPtr p; if(q.size==0)return FALSE; if(q.size==1){ p=q.rear; e=p->data; q.rear=NULL; delete p; } else{ p=q.rear->next; e=p->data; q.rear->next=p->next; delete p; } q.size--; return OK; }
其他解法:
解:算法如下:
//先定义链队结构:
typedef struct queuenode{
Datatype data;
struct queuenode *next;
}QueueNode; //以上是结点类型的定义
typedef struct{
queuenode *rear;
}LinkQueue; //只设一个指向队尾元素的指针
(1)置空队
void InitQueue( LinkQueue *Q)
{ //置空队:就是使头结点成为队尾元素
QueueNode *s;
Q->rear = Q->rear->next;//将队尾指针指向头结点
while (Q->rear!=Q->rear->next)//当队列非空,将队中元素逐个出队
{s=Q->rear->next;
Q->rear->next=s->next;
free(s);
}//回收结点空间
}
(2)判队空
int EmptyQueue( LinkQueue *Q)
{ //判队空
//当头结点的next指针指向自己时为空队
return Q->rear->next->next==Q->rear->next;
}
(3)入队
void EnQueue( LinkQueue *Q, Datatype x)
{ //入队
//也就是在尾结点处插入元素
QueueNode *p=(QueueNode *) malloc (sizeof(QueueNode));//申请新结点
p->data=x; p->next=Q->rear->next;//初始化新结点并链入
Q-rear->next=p;
Q->rear=p;//将尾指针移至新结点
}
(4)出队
Datatype DeQueue( LinkQueue *Q) {//出队,把头结点之后的元素摘下 Datatype t; QueueNode *p; if(EmptyQueue( Q )) Error("Queue underflow"); p=Q->rear->next->next; //p指向将要摘下的结点 x=p->data; //保存结点中数据 if (p==Q->rear) {//当队列中只有一个结点时,p结点出队后,要将队尾指针指向头结点 Q->rear = Q->rear->next; Q->rear->next=p->next;} else Q->rear->next->next=p->next;//摘下结点p free(p);//释放被删结点 return x; }
解:
#define MaxQSize 4 typedef int ElemType; typedef struct{ ElemType *base; int rear; int length; }Queue; Status InitQueue(Queue& q) { q.base=new ElemType[MaxQSize]; if(!q.base) return FALSE; q.rear=0; q.length=0; return OK; } Status EnQueue(Queue& q,ElemType e) { if((q.rear+1)%MaxQSize==(q.rear+MaxQSize-q.length)%MaxQSize) return FALSE; else{ q.base[q.rear]=e; q.rear=(q.rear+1)%MaxQSize; q.length++; } return OK; } Status DeQueue(Queue& q,ElemType& e) { if((q.rear+MaxQSize-q.length)%MaxQSize==q.rear) return FALSE; else{ e=q.base[(q.rear+MaxQSize-q.length)%MaxQSize]; q.length--; } return OK; }
其他写法:
解:根据题意,可定义该循环队列的存储结构:
#define QueueSize 100
typedef char Datatype ; //设元素的类型为char型
typedef struct {
int quelen;
int rear;
Datatype Data[QueueSize];
}CirQueue;
CirQueue *Q;
循环队列的队满条件是:Q->quelen== QueueSize
知道了尾指针和元素个数,当然就能计算出队头元素的位置。算法如下:
(1)判断队满
int FullQueue( CirQueue *Q)
{//判队满,队中元素个数等于空间大小
return Q->quelen== QueueSize;
}
(2)入队
void EnQueue( CirQueue *Q, Datatype x)
{// 入队
if(FullQueue( Q))
Error("队已满,无法入队");
Q->Data[Q->rear]=x;
Q->rear=(Q->rear+1)%QueueSize;//在循环意义上的加1
Q->quelen++;
}
(3)出队
Datatype DeQueue( CirQueue *Q)
{//出队
if(Q->quelen==0)
Error("队已空,无元素可出队");
int tmpfront; //设一个临时队头指针
tmpfront=(QueueSize+Q->rear - Q->quelen+1)%QueueSize;//计算头指针位置
Q->quelen--;
return Q->Data[tmpfront];
}
解:含三个结点的树只有两种:(1)和(2);而含3个结点的二叉树可能有下列3种形态:(一),(二),(三),(四),(五)。
注意,(2)和(三)是完全不同的结构。
解:
解:
解:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。