⑴ c语言的综合设计问题。。。。关于打分系统的排名次问题
case 2:
for(i=0;i<=9;i++) //在外层for循环用的是i变量,而第三层for循环又用到i变量,这两个变量会冲突
for(m=0;m<9;m++)
for(i=0;i=9-m;i++) //应该把i变为j
if(playerscore[i]>playerscore[i+1])
{
a=playerscore[i];
playerscore[i]=playerscore[i+1];
playerscore[i+1]=a;
}
for(i=0;i<10;i++)
printf("%f",playerscore[i]);
break;
问题已经用注释标注,我没有编译过,但是我发现了这个小问题,提出来,不知道得没得
⑵ C语言数据结构中的几种内部排序法,求解!高手速度来指导我。。
1.Shell排序(ShellSort)
Shell排序通过将数据分成不同的组,先对每一组进行排序,然后再对所有的元素进行一次插入排序,以减少数据交换和移动的次数。平均效率是O(nlogn)。其中分组的合理性会对算法产生重要的影响。现在多用D.E.Knuth的分组方法。
Shell排序比冒泡排序快5倍,比插入排序大致快2倍。Shell排序比起QuickSort,MergeSort,HeapSort慢很多。但是它相对比较简单,它适合于数据量在5000以下并且速度并不是特别重要的场合。它对于数据量较小的数列重复排序是非常好的。
2.快速排序(QuickSort)
快速排序是一个就地排序,分而治之,大规模递归的算法。从本质上来说,它是归并排序的就地版本。快速排序可以由下面四步组成。
(1) 如果不多于1个数据,直接返回。
(2) 一般选择序列最左边的值作为支点数据。
(3) 将序列分成2部分,一部分都大于支点数据,另外一部分都小于支点数据。
(4) 对两边利用递归排序数列。
快速排序比大部分排序算法都要快。尽管我们可以在某些特殊的情况下写出比快速排序快的算法,但是就通常情况而言,没有比它更快的了。快速排序是递归的,对于内存非常有限的机器来说,它不是一个好的选择。
3堆排序(HeapSort)
堆排序适合于数据量非常大的场合(百万数据)。
堆排序不需要大量的递归或者多维的暂存数组。这对于数据量非常巨大的序列是合适的。比如超过数百万条记录,因为快速排序,归并排序都使用递归来设计算法,在数据量非常大的时候,可能会发生堆栈溢出错误。
堆排序会将所有的数据建成一个堆,最大的数据在堆顶,然后将堆顶数据和序列的最后一个数据交换。接下来再次重建堆,交换数据,依次下去,就可以排序所有的数据。
下面是一个总的表格(这张表很重要),大致总结了我们常见的所有的排序算法的特点。
排序法 平均时间 最差情形 稳定度 额外空间 备注
冒泡 O(n2) O(n2) 稳定 O(1) n小时较好
交换 O(n2) O(n2) 不稳定 O(1) n小时较好
选择 O(n2) O(n2) 不稳定 O(1) n小时较好
插入 O(n2) O(n2) 稳定 O(1) 大部分已排序时较好
基数 O(logRB) O(logRB) 稳定 O(n)
B是真数(0-9),
R是基数(个十百)
Shell O(nlogn) O(ns) 1<s<2 不稳定 O(1) s是所选分组
快速 O(nlogn) O(n2) 不稳定 O(nlogn) n大时较好
归并 O(nlogn) O(nlogn) 稳定 O(1) n大时较好
堆 O(nlogn) O(nlogn) 不稳定 O(1) n大时较好
备注:O(n2)表示双重循环,即n^2
⑶ 程序设计问题-排序算法
int lnitSqlist(Sqlist *L) 这个要用引用类型。
int lnitSqlist(Sqlist* &L)
不然你的指针里面都是空的。
正常来说,是先声明再写定义 。你都定义好了,这个声明就没必要了。
去掉int lnitSqlist(Sqlist *L);
void Scanfsqlist();
⑷ C语言编程高手请进
这个是我以前编的,有些小错误,你参考一下:
#include"stdio.h"
#include"stdlib.h"
#include"malloc.h"
#include"string.h"
typedef struct stud
{
long int number;
char name[20];
int grade;
char other[30];
char sex[10];
struct stud *next;
}T;
T *creat()
{
T *p,*q,*head;
long int number;
int grade;
char name[20],other[30],sex[10];
head=(T *)malloc(sizeof(T));
q=head;
printf("Please input the data:(num,name,sex,grade,other,0:end)\n");
scanf("%ld",&number);fflush(stdin);
if(number)
{
gets(name);
gets(sex);
scanf("%d",&grade);fflush(stdin);
gets(other);
}
while(number)
{
p=(T *)malloc(sizeof(T));
q->number=number;
strcpy(q->name,name);
strcpy(q->sex,sex);
q->grade=grade;
strcpy(q->other,other);
q->next=p;
q=p;
scanf("%ld",&number);fflush(stdin);
if(number)
{
gets(name);
gets(sex);
scanf("%d",&grade);fflush(stdin);
gets(other);
}
}
q->next=NULL;
fflush(stdin);
return head;
}
void print(T *head)
{
T *p;
p=head;
if(p)
printf("Number name \tsex grade other\n");
while(p->next)
{
printf("%08ld %-15s%-6s %-8d %s\n",p->number,p->name,p->sex,p->grade,p->other);
p=p->next;
}
printf("\nEND!\n");
}
void fprint(T *head,FILE *fp)
{
T *p;
p=head;
if(p)
fprintf(fp,"Number name \tsex grade other\n");
while(p->next)
{
fprintf(fp,"%08ld %-15s%-6s %-8d %s\n",p->number,p->name,p->sex,p->grade,p->other);
p=p->next;
}
fprintf(fp,"\nEND!\n");
}
T *range(T *head)
{
T *p,*q,*s;
int key;
printf("Please input the key you want to range:\n1.number,2.name,3.sex,4.grade,5.other.\nYour choice:[ ]\b\b");
scanf("%d",&key);fflush(stdin);
s=q=head;
p=q->next;
switch(key)
{
case 1:
while(p)
{
if(s->number>p->number) s=p;
p=p->next;
}
if(s!=head)
{
s->next=head;
head=s;
}
for(s=q=head->next;s;s=q=s->next)
{
for(p=q->next;p;p=p->next)
if(s->grade>p->grade) s=p;
if(s!=q)
{
s->next=q;
q=s;
}
}
break;
case 2:
while(p)
{
if(strcmp(s->name,p->name)>0) s=p;
p=p->next;
}
if(s!=head)
{
s->next=head;
head=s;
}
for(s=q=head->next;s;s=q=s->next)
{
for(p=q->next;p;p=p->next)
if(s->grade>p->grade) s=p;
if(s!=q)
{
s->next=q;
q=s;
}
}
break;
case 3:
while(p)
{
if(strcmp(s->sex,p->sex)>0) s=p;
p=p->next;
}
if(s!=head)
{
s->next=head;
head=s;
}
for(s=q=head->next;s;s=q=s->next)
{
for(p=q->next;p;p=p->next)
if(s->grade>p->grade) s=p;
if(s!=q)
{
s->next=q;
q=s;
}
}
break;
case 4:
while(p)
{
if(s->grade>p->grade) s=p;
p=p->next;
}
if(s!=head)
{
s->next=head;
head=s;
}
for(s=q=head->next;s;s=q=s->next)
{
for(p=q->next;p;p=p->next)
if(s->grade>p->grade) s=p;
if(s!=q)
{
s->next=q;
q=s;
}
}
break;
case 5:
while(p)
{
if(strcmp(s->other,p->other)>0) s=p;
p=p->next;
}
if(s!=head)
{
s->next=head;
head=s;
}
for(s=q=head->next;s;s=q=s->next)
{
for(p=q->next;p;p=p->next)
if(s->grade>p->grade) s=p;
if(s!=q)
{
s->next=q;
q=s;
}
}
break;
}
return head;
}
T *range_1(T *head)
{
T *p,*q,*s;
s=q=head;
p=q->next;
while(p)
{
if(s->number>p->number) s=p;
p=p->next;
}
if(s!=head)
{
s->next=head;
head=s;
}
for(s=q=head->next;s;s=q=s->next)
{
for(p=q->next;p;p=p->next)
if(s->grade>p->grade) s=p;
if(s!=q)
{
s->next=q;
q=s;
}
}
return head;
}
T *insert(T *head)
{
T *p,*q,*s;
s=(T *)malloc(sizeof(T));
printf("Please input the insert data:(num,name,sex,grade,other)\n");
scanf("%ld",&s->number);fflush(stdin);
if(s->number==0)
{
printf("ERROR!\nPlease input number again.\n");
scanf("%ld",&s->number);fflush(stdin);
}
gets(s->name);
gets(s->sex);
scanf("%d",&s->grade);fflush(stdin);
gets(s->other);
q=head;
p=q->next;
if(q->number>s->number)
{
s->next=head;
head=s;
}
while(q->number<s->number&&p)
{
q=p;
p=q->next;
}
/*if(!q)
{
q->next=s;
s->next=NULL;
}
else
{
s->next=p;
q->next=s;
}*/
s->next=p;
q->next=s;
return head;
}
T *del(T *head)
{
T *p,*q;
long int x;
int key=2;
print(head);
printf("Please input the data you want to delete:(num)\n");
scanf("%ld",&x);fflush(stdin);
for(;key==2;)
{
printf("Are you sure?\n1.OK.\n2.Input new.\n3.Exit delete.\nYour choice:[ ]\b\b");
scanf("%d",&key);fflush(stdin);
if(key==3) return head;
if(key==2) scanf("%ld",&x);
}
q=head;
p=q->next;
if(q->number==x)
{head=p;return(head);}
while(q&&p->number!=x)
{
q=p;
p=q->next;
}
if(q)
{
q->next=p->next;
free(p);
}
else printf("NOT Found!!!\n");
return head;
}
void prt()
{
printf(" welcome to use!!! \t\t========================\n");
printf(" \t\t* Linklist Student *\n");
printf(" \t\t* by czj *\n");
printf(" \t\t* 2008 10 4 *\n");
printf(" \t\t========================\n");
}
void fprt(FILE *p)
{
fprintf(p," welcome to use!!! \t\t========================\n");
fprintf(p," \t\t* Linklist Student *\n");
fprintf(p," \t\t* by czj *\n");
fprintf(p," \t\t* 2008 10 4 *\n");
fprintf(p," \t\t========================\n");
}
void main()
{
T *head=NULL;
int key=1;
FILE *p;
prt();
head=creat();
print(head);
printf("1.INSERT.\n2.DLETE.\n3.CORRECT.\n4.RANGE.\n0.EXIT.\nYour choice[ ]\b\b");
scanf("%d",&key);fflush(stdin);
for(;key;)
{
system("cls");
prt();
if(key==1) insert(head);
if(key==2||key==3) del(head);
if(key==3) insert(head);
if(key==4) range(head);
print(head);
printf("1.INSERT.\n2.DELETE.\n3.CORRECT.\n4.RANGE.\n0.EXIT.\nYour choice[ ]\b\b");
scanf("%d",&key);fflush(stdin);
}
if((p=fopen("d:\\linklist1.dat","w"))==NULL)
{
printf("Can't open the file.\n");
exit(0);
}
fprt(p);
fprint(head,p);
fclose(p);
}
/*
最后一个节点不用。
fflush(stdin);清除缓存。
insert中输入有问题,range。
*/
⑸ 桶排序算法到底是个什么意思
m#include <iostream>
#include <ctime>
#include <cmath>
using namespace std;
void main()
{
long choice;
long start,end;
MUNE: cout<<"桶排序:1.正常情况 2.最坏情况 3.退出"<<endl;
cin>>choice;
struct node //定义链表
{
double item;
node *next;
node(double x,node *n)
{
item=x;
next=n;
}
};
typedef node *link; //构造链表
const long ARRAYNUM=10000; //定义要求要求排序数组大小
const long BUCKETNUM=10000; //定义桶的数量
double *SortArray;
SortArray=new double[ARRAYNUM];//定义排序数组
link *Bucket;
Bucket=new link[BUCKETNUM]; //定义桶
link t=new node(0,NULL);
link newlink;
link templink=new node(0,NULL);
for (long x=0;x<BUCKETNUM;x++) //初始化桶
{
Bucket[x]=new node(0,NULL);
}
srand((unsigned) time(NULL)); //产生随机数组
for (long i=0;i<ARRAYNUM;i++)
{
SortArray[i]=(double)rand()/RAND_MAX;
}
start=clock(); //设置时钟起点
for(long j=0;j<ARRAYNUM;j++)
{
newlink=new node(SortArray[j],NULL);
switch(choice) //输入选择
{
case 1: t=Bucket[(long)(BUCKETNUM*SortArray[j])];break;
case 2: t=Bucket[0];break; //最坏情况,数据都在一个桶里
case 3: goto EXIT;break;
}
if(t->item==0) //如果桶为空,则把数据直接放入桶内
{
t->item=SortArray[j];
}
else
{
if(t->item>SortArray[j]) //桶不为空,待插入数据比原桶内第一个数据小情况
//即数据要插在第一个数据前面
{
templink=t; //前向指针,随着t的编译,templing->next=t
Bucket[(long)(BUCKETNUM*(newlink->item))]=newlink;
newlink->next=templink;
templink=NULL;
}
else
{
while(t!=NULL) //桶不为空,待插入数据比原桶内数据小情况
{
if(t->item<=SortArray[j]) //桶不为空,待插入数据比原桶内第二个及以后数据大情况,
{
templink=t;
t=t->next; //待插入数比桶内数大,链表后向遍历
if(t==NULL) //链表编译到原桶内最后一个数
{
templink->next=newlink;//将待插数据接在原链表最后
}
}
else //链表比当前数据小,插入数据
{
newlink->next=t;
templink->next=newlink;
t=NULL;
}
}
}
}
}
end=clock(); //设置时钟终点
cout<<"所用时间为:"<<end-start<<endl;
goto MUNE;
EXIT:;
}简单来说,就是把数据分组,放在一个个的桶中,然后对每个桶里面的在进行排序。
例如要对大小为[1..1000]范围内的n个整数A[1..n]排序
可以把桶设为大小为10的范围,具体而言,设集合B[1]存储[1..10]的整数,集合B[2]存储
(10..20]的整数,……集合B[i]存储( (i-1)*10, i*10]的整数,i = 1,2,..100。总共有
100个桶。
然后对A[1..n]从头到尾扫描一遍,把每个A[i]放入对应的桶B[j]中。
然后再对这100个桶中每个桶里的数字排序,这时可用冒泡,选择,乃至快排,一般来说任
何排序法都可以。最后依次输出每个桶里面的数字,且每个桶中的数字从小到大输出,这
样就得到所有数字排好序的一个序列了。
假设有n个数字,有m个桶,如果数字是平均分布的,则每个桶里面平均有n/m个数字。如果
对每个桶中的数字采用快速排序,那么整个算法的复杂度是
O(m + m * n/m*log(n/m)) = O(m + nlogn - nlogm)
从上式看出,当m接近n的时候,桶排序复杂度接近O(n)
当然,以上复杂度的计算是基于输入的n个数字是平均分布这个假设的。这个假设是很强的
,实际应用中效果并没有这么好。如果所有的数字都落在同一个桶中,那就退化成一般的
排序了。
⑹ 银行家算法
#include<string.h>
#include<stdio.h>
#define M 5 //定义进程数
#define N 3 //定义资源数
#define False 0
#define True 1
int Max[5][3]={{7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3}}; //每个进程对每类资源的最大需求
int Allocation[5][3]={{0,1,0},{2,0,0},{3,0,2},{2,1,1},{0,0,2}};//系统已分配资源
int Avaliable[3]={3,3,2}; //系统可利用资源
int Need[5][3]={{7,4,3},{1,2,2},{6,0,0},{0,1,1},{4,3,1}};//还需要资源
int Request[3];
void showdata()//显示资源矩阵
{
int i,j;
printf("系统目前可利用的资源数量:\n A,B,C\n");
printf("resouce: ");
for (j=0;j<N;j++)
printf("%d,",Avaliable[j]);//输出分配资源
printf("\n");
printf("各进程的资源需求:\n");
for (i=0;i<M;i++)
{
printf("pr%d: ",i);
for (j=0;j<N;j++)
{
printf("%d,",Max[i][j]);//输出最大需求资源数
}
printf("\n");
}
printf("各进程得到资源:\n");
for (i=0;i<M;i++)
{
printf("pr%d: ",i);
for(j=0;j<N;j++)
printf("%d,",Allocation[i][j]);//输出已分配资源数
printf("\n");
}
printf("各进程还需求资源:\n");
for (i=0;i<M;i++)
{
printf("pr%d: ",i);
for(j=0;j<N;j++)
printf("%d,",Need[i][j]);//输出还需要资源数
printf("\n");
}
}
void release(int i)//判断是否安全,若不安全则释放第i类资源
{
int j;
for (j=0;j<N;j++)
{
Avaliable[j]=Avaliable[j]+Request[j];
Allocation[i][j]=Allocation[i][j]-Request[j];
Need[i][j]=Need[i][j]+Request[j];
}
}
void distribute(int i)//若符合条件则对第i类资源进行分配
{
int j;
for (j=0;j<M;j++)
{
Avaliable[j]=Avaliable[j]-Request[j];
Allocation[i][j]=Allocation[i][j]+Request[j];
Need[i][j]=Need[i][j]-Request[j];
}
}
void safeAlgorithm()//安全性算法
{
int Work[3],Finish[M]={0},result[M],run;
/* work:表示系统可提供给进程继续运行的所需的各类资源数目
finish: 表示系统是否有足够的资源分配给进程
result用来存放依次执行成功的线程 */
int i,j,k=0,m,demand;
for(i=0;i<3;i++)
{
Work[i]=Avaliable[i]; //开始的时候work=available
}
for(i=0;i<M;i++)
{
demand=0;
for(j=0;j<N;j++)
{
if (Finish[i]==False&&Need[i][j]<=Work[j])
{ demand++;
if(demand==3)//只有ABC三类资源都满足才把相应的线程记入数组result中
{ for(m=0;m<N;m++)
Work[m]=Work[m]+Allocation[i][m];//重新分配第i类线程的当前可利用资源
Finish[i]=True;
result[k]=i;
i=-1;
k++;
}
}
else
if(Finish[i]==False)
{
if(i==M-1)
{ printf("系统不安全\n");//如果不成功,输出系统不安全
run=False; }
break;
}
}
}
printf("系统资源分配成功!");//如果安全,输出成功
printf("分配的序列:\n");
for(i=0;i<M;i++)//输出运行进程数组
{
printf("pr%d ",result[i]);
}
}
void bankerAlgorithm()//利用银行家算法对申请资源对进行判定
{
int i,j,OK=1,run=True;
printf("\n请输入第一个要求分配的资源进程号从(0 to 4):");
scanf("%d",&i);//输入须申请的资源号
printf("请输入进程 %d 申请的资源:\n",i);
for(j=0;j<3;j++)
{
printf("第 %d 个资源:",j+1);
scanf("%d",&Request[j]);//输入需要申请的资源
}
for (j=0;j<N;j++)
{
if(Request[j]>Need[i][j])//判断申请是否大于需求,若大于则出错
{
printf("进程 %d 申请的资源大于它需要的资源",i);
printf(" error!\n");
OK=0;
break;
}
else
{ if(Request[j]>Avaliable[j]) //判断申请是否大于当前资源,若大于则出错
{
printf("进程 %d 申请的资源大于当前可利用资源",i);
printf(" error!\n");
OK=0;
break;
}
}
}
if(OK==1) //若都符合条件,则进行分配
{
distribute(i); //根据进程请求分配资源
showdata(); //显示变换后的资源
safeAlgorithm(); //通过安全算法判断该序列是否安全
if(run==False) //若不安全,则进行释放第I类资源
{ release(i); }
}
}
void main()//主函数
{ int choice;
showdata();
safeAlgorithm();
do
{ printf("\n输入接下来你要进行的操作 1:分配资源 2:显示资源 否则按任意键退出");
scanf("%d",&choice);
switch(choice)
{ case 1: bankerAlgorithm(); break;
case 2: showdata(); break;
default: break;
}
}while((choice==1)||(choice==2));
}
⑺ 拜占庭将军问题的解决算法
拜占庭问题的最初描述是:n 个将军被分隔在不同的地方,忠诚的将军希望通过某种协议达成某个命令的一致(比如一起进攻或者一起后退)。但其中一些背叛的将军会通过发送错误的消息阻挠忠诚的将军达成命令上的一致。Lamport 证明了在将军总数大于3m ,背叛者为m 或者更少时,忠诚的将军可以达成命令上的一致。
为了保证上面的需求,必须满足下面两个条件:
1. 每两个忠诚的将军必须收到相同的值 v(i)(v(i)是第i 个将军的命令)
2. 如果第i 个将军是忠诚的,那么他发送的命令和每个忠诚将军收到的v(i)相同
为了简化以上模型,我们使用一个将军发送命令给多个副官的形式来证明,发送命令的将军称为发令者,接收命令的将军为副官,那么上面的两个条件可以表述为:
IC1. 所有忠诚的副官遵守相同的命令
IC2. 如果发出命令的将军是忠诚的,那么所有忠诚的副官遵守司令(发出命令的将军)的命令
特别提示:发送命令的每次只有一个将军,将其命令发送给n-1 个副官。m 代表叛国者的个数,因为将军总数为n,所以副官总数为n-1 个。IC2 中副官遵守实际上是指忠诚的将军能够正确收到忠诚将军的命令消息。 通过口头消息传递达到一致,如果有m 个叛国将军,则将军们的总数必须为3m+1 个以上。下面是口头消息传递过程中默认的一些条件:
A1. 每个被发送的消息都能够被正确的投递
A2. 信息接收者知道是谁发送的消息
A3. 能够知道缺少的消息
A1 和A2 假设了两个将军之间通信没有干扰,既不会有背叛者阻碍消息的发送(截断)也不会有背叛者伪造消息的情况(伪造)。即是每个将军都可以无误地将自己的消息发送给其他每个将军。(下一节中可以不需要这个必要条件)
我们定义口头消息算法OM(m) 。对于所有的非负整数m ,每个发令者通过OM(M) 算法发送命令给n-1 个副官。下面将说明OM(m) 算法在最多有m 个背叛者且总将军数为3m+1 或者更多的情况下可以解决拜占庭将军问题。(考虑到网络应用实际环境,原文使用了收到值代替收到命令,本文不做修改)
算法定义一个函数:majority(com1,com2,…,comn)等于多数派命令。
OM(0)算法
(1)发令者将他的命令发送给每个副官。
(2)每个副官采用他从发令者得到的命令,或者默认使用撤退命令,如果没有收到任何命令。
OM(m)算法
(1)发令者将他的命令发送给每个副官。
(2)对于每个i ,vi 是每个副官i 从发令者收到的命令,如果没有收到命令则为撤退命令。副官i 在OM(m-1) 中作为发令者将vi 发送给另外n-2 个副官。
(3)对于每个i,并且j
eq i,vj 是副官i 从第(2)步中的副官j 发送过来的命令(使用OM(m-1)算法),如果没有收到第(2)步中的副官j 的命令则默认为撤退命令。最后副官i 使用majority(v1,…,vn-1)得到命令。
接下来实际的考虑一个n=4,m=1 的情况:
1. 当副官D是背叛者
第一步发令者A执行算法OM(1)将自己的命令发送给三个副官B,C,D,三个副官都正确地收到了命令。
第二步每个收到命令的副官都作为发令者执行算法OM(0),将自己收到的命令转发给其余副官,因为副官D是背叛者,所以他给副官B和C传递的消息可能会是假消息。副官B和C分别根据majority 函数来决定命令。
这样背叛的副官D 同理也干扰不了发令者的决定。下面看看如果发令者是背叛者。
2. 发令者是背叛者,其余副官为忠诚的
第一步:发令者A向副官B,C,D发送了不同的命令,实际情况中是一个攻击者向不同方发送了不一致的值(例如,0或1)企图扰乱副官做出一致决定。
第二步:副官收到命令后,摇身一变为发令者执行OM(0) 向所有的副官发送命令,每个副官通过多数表决算法仍可以达成一致的命令。
文章接着就证明了OM(m)算法对任意m 都是可以满足,首先引入一个引理(归纳法证明):
引理1:对于任意m 和k ,如果有超过2k+m 个将军和最多k 个背叛者,那么算法OM(m) 满足IC2 (回顾下IC2 指的是,如果将军是忠诚的,所有的副官遵守将军命令)。
证明:当m=0 的时候,OM(0) 在将军是忠诚的时候满足IC2。当m>0 时,首先将军将命令传递给 n-1 个副官,然后每个副官对n-1 个将军执行OM(m-1) 算法。因为假设了n>2k+m(引理中有将军数大于2k+m),所以 n-1 > 2k+(m-1) >= 2k(即每一轮中副官总数不小于背叛者的两倍),这样每轮OM(m-k) 算法中忠诚的副官收到的命令都是majority(v1,v2,...,v(n-1)),其中忠诚副官发送的命令大于或者等于一半。
接着解决拜占庭将军问题。
定理1:对于任意m,如果有超过3m 个将军和最多m 个背叛者,算法OM(m) 满足条件IC1 和条件IC2。
证明:通过m 的归纳法证明,我们通过假设OM(m-1) 成立来证明OM(m) m>0。首先考虑发送命令的将军是忠诚的。那么将引理中k 设为m 则OM(m) 满足IC2 ,IC1 在发令将军是忠诚的情况下也满足。
接着考虑m 个背叛者中有一个是发令者,那最多就只有m-1 个副官是背叛者了,又因为有3m 个将军,所以副官的总数超过3m-1,且有3m-1>3(m-1) 。因此通过归纳法假设 OM(m-1) 满足IC1 和IC2(最多3(m-1) 个将军和最多m-1 个背叛者)。那么任意两个忠诚的副官j 在OM(m-1) 获得相同命令vj,那么在OM(m) 算法中每个忠诚的副官都会收到(v1,v2,...,v(n-1)),可知满足条件IC1 和IC2。
看完这段证明其实我也挺糊涂的~~~~,画了张图来看看lamport 是怎么证明的:
签名消息在除了满足口头消息A1-A3 三点要求外还应该满足下面A4:
A4 (a)签名不可被伪造,一旦被篡改即可发现
(b)任何人都可以验证将军签名的可靠性
下面定义一个类似于上面majority() 函数的choice() 来决定副官的选择:1.当集合V 只包含了一个元素v ,那么choice(V)=v ;2. choice(o)=RETREAT。
有了上面A4 和choice() 基础我们给出SM(m) 方法:
SM(m) 算法
初始化Vi=空集合
(1)将军签署命令并发给每个副官
(2)对于每个副官i :
(A)如果副官i 从发令者收到v:0 的消息,且还没有收到其他命令序列,那么:
(i)使Vi 为{v}
(ii)发送v:0:i 给其他所有副官
(B)如果副官i 收到消息v:0:j1:...:jk 且v 不在集合Vi 中则
(i)添加v 到Vi
(ii)如果k<m ,那么发送v:0:j1:...:jk:i 给每个不在j1,..,jk 中的副官
(3)对于每个副官i ,当不再收到消息,则遵守命令choive(Vi)
算法的几点说明:
算法第三步并没有说明副官如何判断没有新的消息,可以通过两个解决方法:一是要求每个副官收到消息后要么签名转发该消息,要么发送一个通知他将不发送这个消息;二是设置一个超时时间,如果在该时间段还没有收到消息,则认为不再收到消息。
算法SM(m) 中,让副官签名是确认其收到了该消息(有点像来了份文件给每个领导批阅)。在SM(1) 中副官收到消息就不用签字了,因为不用转发给其他副官。
定理2:对于任意m,最多只有m 个背叛者情况下,算法SM(m) 解决拜占庭将军问题
Proof:首先证明IC2,如果发令者是忠诚的,那么所有的副官一定收到相同的命令,因为签名无法篡改,且IC1 也就满足了。证明IC1 只用考虑发令者是背叛者的情况(重新回顾下IC1 是指所有忠诚的副官执行相同的命令),IC1 要求两个忠诚的副官(i,j)必须收到相同的命令集合Vi、Vj,也就是Vi 中每个v 都在Vj 中。会存在两种情况,其一当副官i 收到v 命令的序列后,加入到Vi,并将其发送给副官j ,j 将命令v 保存;其二副官i 收到命令v:0:j1:...:jk:i,其中有jr=j,所以 由A4 可知副官j 也收到了该命令。如果没有,则有:
k<m。这种情况下,i 发送信息v:0:j1:...:jk:i 给副官j ,那么j 一定收到v 。(这点感觉和上面有重复)
k=m。发令者是背叛者,最多只有m-1 个副官是背叛者。因此,最少有一个序列j1,...,jm是忠诚的。那么j 一定收到这个忠诚的副官序列发来的值v ,所以副官j 收到v 。
证明完毕。
⑻ 康迈臣AHN`S CHOICE的优势在哪里
康迈臣AHN`S CHOICE优势在庞大的数据库、缜密的算法及权威的专家。它集合业界知名的营养学专家,联合有近200家大型知名三甲医院复杂项目建设经验、国家健康管理团体标准制定参与单位的系统开发公司,并且参考中国营养学会,中华医学会健康管理分会等出具的10余种权威文献,打造出现在的庞大系统。 想了解更多可以网络一下
⑼ 计算机算法中的递归法与选择排序法是什么请细讲
递归是设计和描述算法的一种有力的工具,由于它在复杂算法的描述中被经常采用,为此在进一步介绍其他算法设计方法之前先讨论它。
能采用递归描述的算法通常有这样的特征:为求解规模为N的问题,设法将它分解成规模较小的问题,然后从这些小问题的解方便地构造出大问题的解,并且这些规模较小的问题也能采用同样的分解和综合方法,分解成规模更小的问题,并从这些更小问题的解构造出规模较大问题的解。特别地,当规模N=1时,能直接得解。
递归算法的执行过程分递推和回归两个阶段。在递推阶段,把较复杂的问题(规模为n)的求解推到比原问题简单一些的问题(规模小于n)的求解。例如上例中,求解fib(n),把它推到求解fib(n-1)和fib(n-2)。也就是说,为计算fib(n),必须先计算fib(n-1)和fib(n-2),而计算fib(n-1)和fib(n-2),又必须先计算fib(n-3)和fib(n-4)。依次类推,直至计算fib(1)和fib(0),分别能立即得到结果1和0。在递推阶段,必须要有终止递归的情况。例如在函数fib中,当n为1和0的情况。
在回归阶段,当获得最简单情况的解后,逐级返回,依次得到稍复杂问题的解,例如得到fib(1)和fib(0)后,返回得到fib(2)的结果,……,在得到了fib(n-1)和fib(n-2)的结果后,返回得到fib(n)的结果。
在编写递归函数时要注意,函数中的局部变量和参数知识局限于当前调用层,当递推进入“简单问题”层时,原来层次上的参数和局部变量便被隐蔽起来。在一系列“简单问题”层,它们各有自己的参数和局部变量。
由于递归引起一系列的函数调用,并且可能会有一系列的重复计算,递归算法的执行效率相对较低。当某个递归算法能较方便地转换成递推算法时,通常按递推算法编写程序。例如上例计算斐波那契数列的第n项的函数fib(n)应采用递推算法,即从斐波那契数列的前两项出发,逐次由前两项计算出下一项,直至计算出要求的第n项。
选择排序法 是对 定位比较交换法 的一种改进。在讲选择排序法之前我们先来了解一下定位比较交换法。为了便于理解,设有10个数分别存在数组元素a[0]~a[9]中。定位比较交换法是由大到小依次定位a[0]~a[9]中恰当的值(和武林大会中的比武差不多),a[9]中放的自然是最小的数。如定位a[0],先假定a[0]中当前值是最大数,a[0]与后面的元素一一比较,如果a[4]更大,则将a[0]、a[4]交换,a[0]已更新再与后面的a[5]~a[9]比较,如果a[8]还要大,则将a[0]、a[8]交换,a[0]又是新数,再与a[9]比较。一轮比完以后,a[0]就是最大的数了,本次比武的武状元诞生了,接下来从a[1]开始,因为状元要休息了,再来一轮a[1]就是次大的数,也就是榜眼,然后从a[2]开始,比出探花,真成比武大会了,当必到a[8]以后,排序就完成了。
下面给大家一个例子:
mai()
{
int a[10];
int i,j,t;
for ( i = 0; i < 10; i ++ ) scanf("%d",&a[ i ]); /*输入10个数,比武报名,报名费用10000¥ ^_^*/
for ( i = 0; i < 9; i ++ )
for ( j = i + 1; j < 10; j ++)
if ( a[ i ] < a[ j ] ) { t = a[ i ]; a[ i ] = a[ j ]; a[ j ] = t; } /*打不过就要让出头把交椅,不过a[ i ]比较爱面子,不好意思见 a[ j ],让t帮忙*/
for( i = 0; i < 10; i ++) printf("%4d",a[ i ]); /*显示排序后的结果*/
}
好啦,罗嗦了半天总算把定位比较排序法讲完了,这个方法不错,容易理解,就是有点麻烦,一把椅子换来换去,哎~
所以就有了下面的选择排序法,开始的时候椅子谁也不给,放在一边让大家看着,找个人k记录比赛结果,然后发椅子。具体来讲呢就是,改进定位比较排序法,但是这个改进只是一部分,比较的次数没变,该怎么打还是怎么打,就是不用换椅子了。每次外循环先将定位元素的小标i值记录到K,认为a[k]是最大元素其实i=k还是a[ i ]最大,a[k]与后面的元素一一比较,该交换的也是也不换,就是把K的值改变一下就完了,最后在把a[k]与a[ i ]交换,这样a就是最大的元素了。然后进入下一轮的比较。选择排序法与定位比较排序法相比较,比的次数没变,交换的次数减少了。
下面也写个例子:
main()
{
int a[10];
int i,j,t,k;
for ( i = 0; i < 10; i ++ ) scanf("%d",&a[ i ]); /*输入10个数,比武报名,报名费用10000¥ ^_^*/
for ( i = 0; i < 9; i ++ )
{ k = i; /*裁判AND记者实时追踪报道比赛情况*/
for ( j = i + 1; j < 10; j ++)
if ( a[ k ] < a[ j ] ) k = j;
t = a[ i ]; a[ i ] = a[ k ]; a[ k ] = t; /* t 发放奖品*/
}
for( i = 0; i < 10; i ++) printf("%4d",a[ i ]); /*显示排序后的结果*/
}
⑽ 康迈臣AHN`S CHOICE是做什么的
康迈臣AHN`S CHOICE是做精准定制营养素项目的。用科学与系统赋能,实现用户足不出户,通过科学的问卷设计与大数据算法,精准捕捉其的独特营养需求,并匹配专业安全的营养补充方案,一站式解决问询、建档、分析、健康定制、产品配送等全链条服务。精准内容设定上,康迈臣AHN`S CHOICE基于每个人的年龄、性别、健康史、躯体症状、生活方式、心理健康、睡眠健康、剂量超标风险、药物相互作用风险等综合评估,找出营养状况不良的人群或有营养改善需求的人群,经过严谨的逻辑算法后,给出高度个性化定制的产品方案,并且给出改善不良生活方式的建议。 想了解更多可以网络一下