(1)给出算法的基本设计思想。
要求在时间上尽可能高效,因此采用空间换时间的方法。分配一个用于标记的数组B[n],用于记录A中是否出现了1到n中的正整数,B[0]对应正整数1,B[n=1]对应正整数n,初始化B中全部为0。由于A中含有n个整数,因此可能返回的值是1到n+1,当A中n个数恰好为1~n时返回n+1,当数组A中出现了小于等于0或大于n的值,可以不采取任何操作。经过以上分析可以得出算法流程:从A[0]开始遍历A,若0 (2)根据设计思想,采用C或C++语言描述算法,关键之处给出解释。
算法实现:
int findMissMin(int A[],int n) {
int i,*B; //标记数组
B=(int *)malloc(sizeof(int)*n); //分配空间
memset(B,0,sizeof(int)*n); //赋初值为0
for (i = 0; i < n;i++)
if (A[i]>0&&A[i]<=n) //若A[i]的值介于1~n,则标记数组B
B[A[i] - 1] = 1;
for (i = 0; i < n;i++) //扫描数组B,找到目标值
if (B[i]==0) break;
return i+1; //返回结果
}
(3)说明你所设计算法的时间复杂度和空间复杂度。
时间复杂度:遍历A一次,遍历B一次,两次循环的操作步骤为O(1)量级,因此时间复杂度为O(n)。空间复杂度:额外分配了B[n],空间复杂度为O(n).
附完整代码:
#include
#include
#include
using namespace std;
int findMissMin(int A[],int n) {
int i,*B; //标记数组
B=(int *)malloc(sizeof(int)*n); //分配空间
memset(B,0,sizeof(int)*n); //赋初值为0
//遍历数组A[n]给B[n]赋标记值
for (i = 0; i < n;i++)
if (A[i]>0&&A[i]<=n) //若A[i]的值介于1~n,则标记数组B
B[A[i] - 1] = 1;
for (i = 0; i < n;i++) //找到第一个满足B[i]=0的下标i
if (B[i]==0) break;
//说明A[n]中的标记值全为1,也就是说A[i]的值一一对应1
return i+1;
}
int main(){
int A1[] = {-5,3,2,3};
//获取数组的最大值
cout <<"数组{-5,3,2,3}中未出现的最小正整数是:"<< findMissMin(A1,4) << endl;
int A2[] = {1,2,3};
cout << "数组{1,2,3}中未出现的最小正整数是:" << findMissMin(A2, 3) << endl;
int A3[] = { 1,5,6,2,0,88};
cout << "数组{1,5,6,2,0,88}中未出现的最小正整数是:" << findMissMin(A3, 6) << endl;
system("pause");
}
(1)给出算法的基本设计思想。
①使用Dmin记录所有已处理的三元组的最小距离,初值为一个足够大的整数。
②集合S1、S2和S3分别保存在数组A、B、C中。数组的下标变量i=j=k=0,当i<|S1|,j<|S2|且k<|S3|时,(S表示集合中的元素个数),循环执行下面的a)~c)。
a)计算(A[i],B[j],C[k])的距离D;(计算D)
b)若D
③输出Dmin,结束。
(2)根据设计思想,采用C或C++语言描述算法,关键之处给出解释。
算法实现:
#define INT_MAX 0x7fffffff
int abs_(int a){ //计算绝对值
if(a<0) return -a;
else return a;
}
bool xls_min(int a,int b,int c){ //a是否是三个数中的最小值
if(a<=b&&a<=c) return true;
return false;
}
int findMinofTrip(int A[],int n,int B[],int m,int C[],int p){
//D_min用于记录三元组的最小距离,初值赋为INT_MAX
int i=0,j=0,k=0,D_min=INT_MAX,D;
while(i<n&&j<m&&k<p&&D_min>0){
cout<<A[i]<<' '<<B[j]<<' '<<C[k]<<endl;
D=abs_(A[i]-B[j])+abs_(B[j]-C[k])+abs_(C[k]-A[i]); //计算D
if(D<D_min) D_min=D; //更新D
if(xls_min(A[i],B[j],C[k])) i++; //更新a
else if(xls_min(B[j],C[k],A[i])) j++;
else k++;
}
return D_min;
}
(3)说明你说设计算法的时间复杂度和空间复杂度。
设n=(|S1|+|S2|+|S3|),时间复杂度为O(n),空间复杂度为O(1)。
附完整代码:
#include
using namespace std;
int abs_(int a){ //计算绝对值
if(a<0) return -a;
else return a;
}
bool xls_min(int a,int b,int c){ //a是否是三个数中的最小值
if(a<=b&&a<=c) return true;
return false;
}
int findMinofTrip(int A[],int n,int B[],int m,int C[],int p){
//D_min用于记录三元组的最小距离,初值赋为INT_MAX
int i=0,j=0,k=0,D_min=INT_MAX,D;
while(i<n&&j<m&&k<p&&D_min>0){
cout<<A[i]<<' '<<B[j]<<' '<<C[k]<<endl;
D=abs_(A[i]-B[j])+abs_(B[j]-C[k])+abs_(C[k]-A[i]); //计算D
if(D<D_min) D_min=D; //更新D
if(xls_min(A[i],B[j],C[k])) i++; //更新a
else if(xls_min(B[j],C[k],A[i])) j++;
else k++;
}
return D_min;
}
int main(){
int A[] = {-1,0,9};
int B[] = {-25,-10,10,11};
int C[] = {2,9,17,30,41};
cout <<"最小距离是:"<< findMinofTrip(A,3,B,4,C,5) << endl;
}
算法实现(递归):
void R_Print(LinkList L){
//从尾到头输出单链表L中每个结点的值
if(L->next!=NULL){
R_Print(L->next); //递归
}
if(L!=NULL) printf(L->data);
}
void R_Ignore_Head(LinkList L){
if(L!=NULL) R_Print(L->next);
}
附完整代码:
#include
#include
#include
#include
#define ERROR 0
#define OK 1
typedef char ElemType;
typedef int Status;
typedef struct LNode {
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//操作结果:构造一个空的线性单链表L
Status ListInit_L(LinkList &L){
L=(LinkList)malloc(sizeof(LNode));//头结点申请地址
if(!L){//if(L==NULL)
printf("分配内存失败!\n");
exit(OVERFLOW);
}
else
L->next=NULL;
return OK;
}
//初始条件:线性单链表L已存在
//操作结果:逆位序输入n个元素的值,建立带表头结点的线性单链表 L(头插法)
void ListCreate_L(LinkList &L,int n){
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;//先建立一个带头结点的单链表
LinkList p;
srand(unsigned(time(0))); //初始化随机数种子
printf("请输入你要插入的元素值(用空格隔开):");
for(int i=n;i>0;--i){
p=(LinkList)malloc(sizeof(LNode));//生成新结点
p->data=rand()%100+1; //随机生成100以内的数字,比scanf()操作简单些
//插入到表头
p->next=L->next;
L->next=p; //将结点p连接在头结点L之后
}
printf("\n");
}
//初始条件:线性单链表L已存在
//操作结果:将L重置为空表
Status ListClear_L(LinkList &L){
LinkList p=L->next;//p指向第一个结点
LinkList q;
while(p)//没到表尾
{
q=p->next;
free(p);
p=q;
}
L->next=NULL;//头结点指针域为空
return OK;
}
//初始条件:线性单链表L已存在
//操作结果:销毁线性单链表L
Status ListDestroy_L(LinkList &L){
LinkList p;
while(L)
{
p=L;
L=L->next;
free(p);
}
return OK;
}
//操作结果:显示单链表各个元素
Status ListDis_L(LinkList &L){
LinkList p=L->next;
if(!p){
printf("这是一个空目录!\n");
return ERROR;
}
printf("单链表:\n");
while(p){
printf("%d ",p->data);
p=p->next;
}
printf("\n");
return OK;
}
//递归:从尾到头输出单链表L中每个结点的值
void R_Print(LinkList L){
if(L->next!=NULL){
R_Print(L->next); //递归
}
if(L!=NULL) printf("%d ",L->data);
}
void R_Ignore_Head(LinkList L){
if(L!=NULL) R_Print(L->next);
}
int main(){
LinkList h;
ListInit_L(h);
ElemType e;
int k,i;
ListCreate_L(h,10);
ListDis_L(h);
printf("逆置L\n");
R_Ignore_Head(h);
ListClear_L(h);
printf("\n销毁后线性单链表L的元素为:\n",ListDestroy_L(h));
system("pause");
return 0;
}
算法实现:
void Sort(LinkList &L){
LNode *p=L->next,*pre;
LNode *r=p->next; //r保持*p后继结点指针,以保证不断链
p->next=NULL; //构造只含一个数据结点的有序表
p=r;
while(p!=NULL){
r=p->next; //保存*p的后继结点指针
pre=L;
while(pre->next!=NULL&&pre->next->data<p->data)
pre=pre->next; //在有序表中查找插入*p的前驱节点*pre
p->next=pre->next; //将*p插入到*pre之后
pre->next=p;
p=r; //扫描原单链表中剩下的结点
}
}
附完整代码:
#include
#include
#include
#include
#define ERROR 0
#define OK 1
typedef char ElemType;
typedef int Status;
typedef struct LNode {
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//操作结果:构造一个空的线性单链表L
Status ListInit_L(LinkList &L){
L=(LinkList)malloc(sizeof(LNode));//头结点申请地址
if(!L){//if(L==NULL)
printf("分配内存失败!\n");
exit(OVERFLOW);
}
else
L->next=NULL;
return OK;
}
//初始条件:线性单链表L已存在
//操作结果:逆位序输入n个元素的值,建立带表头结点的线性单链表 L(头插法)
void ListCreate_L(LinkList &L,int n){
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;//先建立一个带头结点的单链表
LinkList p;
srand(unsigned(time(0))); //初始化随机数种子
printf("请输入你要插入的元素值(用空格隔开):");
for(int i=n;i>0;--i){
p=(LinkList)malloc(sizeof(LNode));//生成新结点
p->data=rand()%100+1; //随机生成100以内的数字,比scanf()操作简单些
//插入到表头
p->next=L->next;
L->next=p; //将结点p连接在头结点L之后
}
printf("\n");
}
//初始条件:线性单链表L已存在
//操作结果:将L重置为空表
Status ListClear_L(LinkList &L){
LinkList p=L->next;//p指向第一个结点
LinkList q;
while(p)//没到表尾
{
q=p->next;
free(p);
p=q;
}
L->next=NULL;//头结点指针域为空
return OK;
}
//初始条件:线性单链表L已存在
//操作结果:销毁线性单链表L
Status ListDestroy_L(LinkList &L){
LinkList p;
while(L)
{
p=L;
L=L->next;
free(p);
}
return OK;
}
//操作结果:显示单链表各个元素
Status ListDis_L(LinkList &L){
LinkList p=L->next;
if(!p){
printf("这是一个空目录!\n");
return ERROR;
}
while(p){
printf("%d ",p->data);
p=p->next;
}
printf("\n");
return OK;
}
//将单链表L的结点重排,使其递增有序
void Sort(LinkList &L){
LNode *p=L->next,*pre;
LNode *r=p->next; //r保持*p后继结点指针,以保证不断链
p->next=NULL; //构造只含一个数据结点的有序表
p=r;
while(p!=NULL){
r=p->next; //保存*p的后继结点指针
pre=L;
while(pre->next!=NULL&&pre->next->data<p->data)
pre=pre->next; //在有序表中查找插入*p的前驱节点*pre
p->next=pre->next; //将*p插入到*pre之后
pre->next=p;
p=r; //扫描原单链表中剩下的结点
ListDis_L(L); //查看单链表L递增排序的过程
}
}
int main(){
LinkList h;
ListInit_L(h);
ElemType e;
int k,i;
ListCreate_L(h,10);
ListDis_L(h);
printf("重排L递增\n");
Sort(h);
ListClear_L(h);
printf("销毁后线性单链表L的元素为:\n",ListDestroy_L(h));
system("pause");
return 0;
}
代码调试过程
算法实现:
//L是带头结点的单链表的头指针,本算法按递增顺序输出单链表中的数据元素
void Min_Delete(LinkList &L){
while(L->next!=NULL){ //循环到仅剩头结点
LNode *pre=L; //pre为元素最小值结点的前驱节点的指针
LNode *p=pre->next; //p为工作指针
while(p->next!=NULL){
if(p->next->data<pre->next->data)
pre=p; //记住当前最小值结点的前驱
p=p->next;
}
printf("%d\n",pre->next->data); //输出元素最小值结点的元素
LinkList u=pre->next; //删除元素值最小的结点
pre->next=u->next;
free(u);
}
free(L); //释放头结点
}
完整代码:
#include
#include
#include
#include
#define ERROR 0
#define OK 1
typedef char ElemType;
typedef int Status;
typedef struct LNode {
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//操作结果:构造一个空的线性单链表L
Status ListInit_L(LinkList &L){
L=(LinkList)malloc(sizeof(LNode));//头结点申请地址
if(!L){//if(L==NULL)
printf("分配内存失败!\n");
exit(OVERFLOW);
}
else
L->next=NULL;
return OK;
}
//初始条件:线性单链表L已存在
//操作结果:逆位序输入n个元素的值,建立带表头结点的线性单链表 L(头插法)
void ListCreate_L(LinkList &L,int n){
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;//先建立一个带头结点的单链表
LinkList p;
srand(unsigned(time(0))); //初始化随机数种子
printf("请输入你要插入的元素值(用空格隔开):");
for(int i=n;i>0;--i){
p=(LinkList)malloc(sizeof(LNode));//生成新结点
p->data=rand()%100+1; //随机生成100以内的数字,比scanf()操作简单些
//插入到表头
p->next=L->next;
L->next=p; //将结点p连接在头结点L之后
}
printf("\n");
}
//初始条件:线性单链表L已存在
//操作结果:将L重置为空表
Status ListClear_L(LinkList &L){
LinkList p=L->next;//p指向第一个结点
LinkList q;
while(p)//没到表尾
{
q=p->next;
free(p);
p=q;
}
L->next=NULL;//头结点指针域为空
return OK;
}
//初始条件:线性单链表L已存在
//操作结果:销毁线性单链表L
Status ListDestroy_L(LinkList &L){
LinkList p;
while(L)
{
p=L;
L=L->next;
free(p);
}
return OK;
}
//操作结果:显示单链表各个元素
Status ListDis_L(LinkList &L){
LinkList p=L->next;
if(!p){
printf("这是一个空目录!\n");
return ERROR;
}
while(p){
printf("%d ",p->data);
p=p->next;
}
printf("\n");
return OK;
}
//L是带头结点的单链表的头指针,本算法按递增顺序输出单链表中的数据元素
void Min_Delete(LinkList &L){
while(L->next!=NULL){ //循环到仅剩头结点
LNode *pre=L; //pre为元素最小值结点的前驱节点的指针
LNode *p=pre->next; //p为工作指针
while(p->next!=NULL){
if(p->next->data<pre->next->data) pre=p; //记住当前最小值结点的前驱
p=p->next;
}
printf("%d\n",pre->next->data); //输出元素最小值结点的元素
ListDis_L(L); //删除最小值之后的单链表中的元素
LinkList u=pre->next; //删除元素值最小的结点
pre->next=u->next;
free(u);
}
free(L); //释放头结点
}
int main(){
LinkList h;
ListInit_L(h);
ElemType e;
int k,i;
ListCreate_L(h,10);
ListDis_L(h);
printf("从小到大排序L\n");
Min_Delete(h);
ListClear_L(h);
printf("\n销毁后线性单链表L的元素为:\n",ListDestroy_L(h));
system("pause");
return 0;
}
算法实现:
//合并两个递增有序链表(带头结点),并使合并后的链表递减排列
void MergeList(LinkList &La, LinkList &Lb){
LNode *r,*pa = La->next,*pb = Lb->next; //分别是表La和Lb的工作指针
La->next = NULL; //La作为结果链表的头指针,先将结果链表初始化为空
while(pa && pb) //当两链表均不为空时,循环
if(pa->data <= pb->data){
r=pa->next; //r暂存pa的后继结点指针
pa->next=La->next;
La->next=pa; //将pa结点链于结果表中,同时逆置(头插法)
pa=r; //恢复pa为当前待比较结点
}
else{
r=pb->next; //r暂存pb的后继结点指针
pb->next=La->next;
La->next=pb; //将pb结点链于结果表中,同时逆置(头插法)
pb=r; //恢复pb为当前待比较结点
}
if(pa)
pb = pa;
while(pb){ //处理剩下的一个非空链表
r=pb->next; //依次插入到La中(头插法
pb->next=La->next;
La->next=pb;
pb=r;
}
free(La);
}
完整代码:
法一:
#include
#include
#include
#include
using namespace std;
typedef char ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
LinkList CreateList(){
LinkList L;
ElemType c;
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
LNode *p , *tail;
tail = L;
c = getchar();
while(c != '#'){
p = (LNode *)malloc(sizeof(LNode));
p->data = c;
tail->next = p;
tail = p;
c = getchar();
}
tail->next = NULL;
return L;
}
void ShowList(LinkList L){
LNode *p;
p = L->next;
while(p != NULL){
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
//合并两个递增有序链表(带头结点),并使合并后的链表递减排列
LinkList MergeList(LinkList &La, LinkList &Lb){
LNode *r,*pa = La->next,*pb = Lb->next; //分别是表La和Lb的工作指针
La->next = NULL; //La作为结果链表的头指针,先将结果链表初始化为空
while(pa && pb) //当两链表均不为空时,循环
if(pa->data <= pb->data){
r=pa->next; //r暂存pa的后继结点指针
pa->next=La->next;
La->next=pa; //将pa结点链于结果表中,同时逆置(头插法)
pa=r; //恢复pa为当前待比较结点
}
else{
r=pb->next; //r暂存pb的后继结点指针
pb->next=La->next;
La->next=pb; //将pb结点链于结果表中,同时逆置(头插法)
pb=r; //恢复pb为当前待比较结点
}
if(pa)
pb = pa;
while(pb){ //处理剩下的一个非空链表
r=pb->next; //依次插入到La中(头插法
pb->next=La->next;
La->next=pb;
pb=r;
}
return La;
}
int main(){
LinkList La,Lb,Lc;
La = CreateList();
getchar();
Lb = CreateList();
cout << "La:" << endl;
ShowList(La);
cout << "Lb:" << endl;
ShowList(Lb);
Lc= MergeList(La, Lb);
cout << "MergeList:" << endl;
ShowList(Lc);
return 0;
}
法二:
#include
#include
#include
using namespace std;
typedef char ElemType;
typedef int Status;
typedef struct LNode {
ElemType data;
struct LNode *next;
}LNode,*LinkList;
LinkList CreateList(){
LinkList L;
ElemType c;
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
LNode *p , *tail;
tail = L;
c = getchar();
while(c != '#'){
p = (LNode *)malloc(sizeof(LNode));
p->data = c;
tail->next = p;
tail = p;
c = getchar();
}
tail->next = NULL;
return L;
}
//操作结果:将L重置为空表
Status ListClear_L(LinkList &L){
LinkList p=L->next;//p指向第一个结点
LinkList q;
while(p){ //没到表尾
q=p->next;
free(p);
p=q;
}
L->next=NULL;//头结点指针域为空
return 1;
}
//操作结果:销毁线性单链表L
Status ListDestroy_L(LinkList &L){
LinkList p;
while(L)
{
p=L;
L=L->next;
free(p);
}
return 1;
}
//操作结果:显示单链表各个元素
Status ListDis_L(LinkList L){
LNode *p;
p = L->next;
while(p != NULL){
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
void ReverseList(LinkList L){
LNode *p, *q;
p = L->next;
L->next = NULL;
while(p != NULL){
q = p->next;
p->next = L->next;
L->next = p;
p = q;
}
}
LinkList MergeList2(LinkList LA, LinkList LB){
ReverseList(LA);
ReverseList(LB);
LinkList LC;
LNode *pa, *pb, *r;
pa = LA->next;
pb = LB->next;
LC = LA;
LC->next = NULL;
r = LC;
while(pa != NULL && pb != NULL){
if(pa->data <= pb->data){
r->next = pb;
r = pb;
pb = pb->next;
}
else{
r->next = pa;
r = pa;
pa = pa->next;
}
if(pa){
r->next = pa;
}
else{
r->next = pb;
}
}
return LC;
}
int main(){
LinkList LA,LB,LC;
LA = CreateList();
getchar();
LB = CreateList();
cout << "LA:" << endl;
ListDis_L(LA);
cout << "LB:" << endl;
ListDis_L(LB);
LC = MergeList2(LA, LB);
cout << "MergeList2:" << endl;
ListDis_L(LC);
return 0;
}