说明
- 本文参照严蔚敏《数据结构(C语言版)题集》一书中包含的问答题和算法设计题目,提供解答和算法的解决方案。
- 请读者在自己已经解决了某个题目或进行了充分的思考之后,再参考本解答,以保证复习效果。
- 由于作者水平所限,本解答中一定存在不少这样或者那样的错误和不足,希望读者们在阅读中多动脑、勤思考,争取发现和纠正这些错误,写出更好的算法来。
2.12 设 A = ( a 1 , ⋯ , a m ) A=(a_1,\cdots{,}a_m) A=(a1,⋯,am)和 B = ( b 1 , ⋯ , b n ) B=(b_1,\cdots{,}b_n) B=(b1,⋯,bn)均为顺序表
A
′
A'
A′和
B
′
B'
B′分别为
A
A
A和
B
B
B中除去最大共同前缀后的子表,
例如,
A
=
(
x
,
y
,
y
,
z
,
x
,
z
)
A=(x,y,y,z,x,z)
A=(x,y,y,z,x,z),
B
=
(
x
,
y
,
y
,
z
,
y
,
x
,
x
,
z
)
B=(x,y,y,z,y,x,x,z)
B=(x,y,y,z,y,x,x,z),
则两者中最大的共同前缀为
(
x
,
y
,
y
,
z
)
(x,y,y,z)
(x,y,y,z),
在两表中除去最大公共前缀后的子表分别为:
A
′
=
(
x
,
z
)
A'=(x,z)
A′=(x,z)和
B
′
=
(
y
,
x
,
x
,
z
)
B'=(y,x,x,z)
B′=(y,x,x,z)。
若
A
′
=
B
′
=
A'=B'=
A′=B′=空表,则
A
=
B
A=B
A=B;
若
A
′
=
A'=
A′=空表,而
B
′
≠
B'\ne
B′=空表,或者两者均不为空表,
且
A
′
A'
A′的首元小于
B
′
B'
B′的首元,则
A
<
B
A<B
A<B;否则
A
>
B
A>B
A>B。
试写一个比较
A
,
B
A,B
A,B大小的算法;
请注意:在算法中,不要破坏原表
A
A
A和
B
B
B,并且,也不一定先求得
A
′
A'
A′和
B
′
B'
B′才进行比较。
解:
用同一个下标变量控制两个线性表。注意你的算法对空表也应能正确执行。
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
#define MAX_TEST_LENGTH 50
#define MAX_TEST_ELEM 26
typedef char ElemType;
typedef struct{
ElemType *elem; // 存储空间基址
int length; // 当前长度
int listsize; // 当前分配的存储容量
} SqList; // 顺序表类型
typedef struct LNode{
ElemType data;
struct LNode *next;
} LNode, *LinkList; // 线性链表类型
Status InitList_Sq(SqList *pL){
// 构造一个空的线性表
(*pL).elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if(!(*pL).elem) exit(OVERFLOW); // 存储分配失败
(*pL).length = 0; // 空表长度为0
(*pL).listsize = LIST_INIT_SIZE; // 初始存储容量
return OK;
}// InitList_Sq
Status ListInsert_Sq(SqList *pL, int i, ElemType e){
// 在顺序线性表L中第i个位置之前插入新的元素e
// i的合法值范围:[1,ListLength_Sq(L)+1]
if(i<1 || i>((*pL).length+1)) return ERROR; // i值不合法
if((*pL).length>=(*pL).listsize){ // 当前存储空间已满,增加分配
ElemType *newbase = (ElemType *)realloc((*pL).elem,((*pL).listsize+LISTINCREMENT)*sizeof(ElemType));
if(!newbase) exit(OVERFLOW); // 存储分配失败
(*pL).elem = newbase; // 新基址
(*pL).listsize += LISTINCREMENT; // 增加存储容量
}
ElemType *p = NULL;
ElemType *q = &((*pL).elem[i-1]); // q为插入位置
for(p=&((*pL).elem[(*pL).length-1]);p>=q;--p) *(p+1) = *p; // 插入位置及之后的元素右移
*q = e; // 插入e
++((*pL).length); // 表长增1
return OK;
}// ListInsert_Sq
Status FreeList_Sq(SqList *pL){
// 释放线性表
if(NULL!=(*pL).elem){
free((*pL).elem);
return OK;
}else{
return ERROR;
}
}// FreeList_Sq
Status rand_init_two_list(SqList *pL, SqList *qL){
time_t t;
int c1,c2,count = MAX_TEST_LENGTH;
if(OK!=InitList_Sq(pL)) return ERROR;
if(OK!=InitList_Sq(qL)) return ERROR;
srand((unsigned)time(&t)); //初始化随机数发生器
c1 = rand()%MAX_TEST_LENGTH;
while(c1--){
if(OK!=ListInsert_Sq(pL,1+rand()%((*pL).length+1),'A'+(rand()%MAX_TEST_ELEM)))
return ERROR; // 随机找一个合法位置插入新随机元素
}
c2 = rand()%MAX_TEST_LENGTH;
while(c2--){
if(OK!=ListInsert_Sq(qL,1+rand()%((*qL).length+1),'A'+(rand()%MAX_TEST_ELEM)))
return ERROR; // 随机找一个合法位置插入新随机元素
}
return OK;
}
void display_two_list(SqList La, SqList Lb){
int i;
printf("List A:\n");
if(!La.length) printf("List A is empty.");
for(i=1;i<=La.length;i++){
printf("%c",La.elem[i-1]);
}
printf("\nList B:\n");
if(!Lb.length) printf("List B is empty.\n");
for(i=1;i<=Lb.length;i++){
printf("%c",Lb.elem[i-1]);
}
putchar('\n');
}
void the_same_prefix(SqList *pL, SqList *qL){
// 随机使两表有相同前缀
time_t t;
int len,choice;
srand((unsigned)time(&t));
len=(*pL).length<(*qL).length?(*pL).length:(*qL).length;
len=rand()%(len+1);
choice = rand()%2;
if(choice) (*pL).length=(*qL).length=len;
while(len--) (*pL).elem[len]=(*qL).elem[len];
}
void test_list_null(SqList *pL, SqList *qL){
// 随机将两表长度变为0,为空表
time_t t;
srand((unsigned)time(&t));
int choice = rand()%3;
if(choice==0){
(*pL).length=0;
}else if(choice==1){
(*qL).length=0;
}else{
(*pL).length=(*qL).length=0;
}
}
void free_two_list(SqList *pL, SqList *qL){
if(OK==FreeList_Sq(pL))
printf("\nFree List A success!");
if(OK==FreeList_Sq(qL))
printf("\nFree List B success!\n");
}
int ListComp(SqList A,SqList B){
int i;
//比较字符表A和B,并用返回值表示结果,值为1,表示A>B;值为-1,表示A<B;值为0,表示A=B
for(i=0;i<A.length&&i<B.length;i++)
if(A.elem[i]!=B.elem[i])
return A.elem[i]>B.elem[i]?1:-1;
if(A.length==B.length) return 0;
//当两个字符表可以互相比较的部分完全相同时,哪个较长,哪个就较大
return A.length>B.length?1:-1;
}//ListComp
int main(){
SqList La,Lb;
int result;
if(OK==rand_init_two_list(&La,&Lb)){
display_two_list(La,Lb);
result=ListComp(La,Lb);
if(result==1) printf("A>B\n");
else if(result==-1) printf("A<B\n");
else printf("A=B\n");
putchar('\n');
// 测试两表有相同前缀,有可能相等
the_same_prefix(&La,&Lb);
display_two_list(La,Lb);
result=ListComp(La,Lb);
if(result==1) printf("A>B\n");
else if(result==-1) printf("A<B\n");
else printf("A=B\n");
putchar('\n');
// 测试随机将其中一个表变空,或者两表都为空
test_list_null(&La,&Lb);
display_two_list(La,Lb);
result=ListComp(La,Lb);
if(result==1) printf("A>B\n");
else if(result==-1) printf("A<B\n");
else printf("A=B\n");
free_two_list(&La,&Lb);
}
return 0;
}
2.13 试写一算法
在带头结点的单链表结构上实现线性表操作LOCATE(L,X)。
解:
上面用动态开辟空间建立和扩展数组,这里用数组来表达静态链表,为什么会这样?
这和我们通常遇到问题的规模有关,一般需要存在数组中可顺序随机存取的数据,
往往需要很大的空间,这样空间的大小往往是我们预料不到的,
所以不得不求助链式开辟,获得一个相对较大的堆空间,而不会形成碎片。
但是链表不一样,互相之间有链式关系的模式通常是有限的,其规模是可以预测到的,
比如树、图和网。所以,从动态数组到静态链表,它们各自取长补短、相辅相成。
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
// 线性表的静态单链表存储结构
#define MAXSIZE 20
typedef int ElemType;
typedef struct{
ElemType data;
int cur;
}component, SLinkList[MAXSIZE];
#define MAX_TEST_ELEM 1000
void InitSpace_SL(SLinkList space){
// 将一维数组space中各分量链成一个备用链表
// space[0].cur为头指针,0表示空指针
int i;
for(i=0;i<MAXSIZE-1;++i) space[i].cur=i+1;
space[MAXSIZE-1].cur=0;
} // InitSpace_SL
void rand_init_space_data(SLinkList space){
// 随机生成静态链表中每个元素的数据
int i;
time_t t;
srand((unsigned)time(&t)); //初始化随机数发生器
for(i=0;i<MAXSIZE;++i) space[i].data=rand()%MAX_TEST_ELEM;
}
void init_order_space_data(SLinkList space){
// 有序生成静态链表中每个元素的数据
int i;
for(i=0;i<MAXSIZE;++i) space[i].data=i;
}
void display_space(SLinkList space){
// 显示静态链表
int i;
for(i=space[0].cur;i;i=space[i].cur)
printf("space[%d].data=%d,next=%d\n",i,space[i].data,space[i].cur);
}
int LocateElem_SL(SLinkList s,ElemType x){
// 在静态链表中查找第一个值为x的元素
// 若找到,则返回它在链表中的位序,否则返回0
int i;
for(i=s[0].cur;i&&s[i].data!=x;i=s[i].cur);
return i;
}
int main(){
int x;
SLinkList space;
InitSpace_SL(space);
printf("Ordered List:\n");
init_order_space_data(space);
display_space(space);
printf("\nRand List's data:\n");
rand_init_space_data(space);
display_space(space);
printf("Input x and locate its position:");
scanf("%d",&x);
printf("Locate x in List,pos=%d",LocateElem_SL(space,x));
return 0;
}