这是最原初,也是众所周知的最慢的算法了。他的名字的由来因为它的工作看来象是冒泡:
#include <iostream.h>
//统计substr在str中的个数
int fun(char *str,char *substr)
{
int n=0;
char *q;
q=substr;
while(*str!='\0')
{
if(*str==*substr)
{
str++;
substr++;
if(*substr=='\0')
{
n++;
substr=q;
}
}
else
{
str++;substr=q;
}
}
return n;
}使用数组实现约瑟夫环:
#include <stdio.h>
#include <stdlib.h>
main()
{
int m,n,i=1,j,k=1,per,o;
printf("请输进总共的人数,记为n \n");
scanf("%d",&n);
int array[n+1];
int order[n+1];
printf("请输进几号出圈,记为m \n");
scanf("%d",&m);
printf("\n**************************************\n");
for(;i <n;i++)//数组链表模拟
array[i]=i+1;
array[n]=1;
printf("%d ",array[n]);
i=1;j=1;per=n;
while(array[i]!=i){
if(k==m){
order[j]=i;
j++;
array[per]=array[i];
k=0;
for(o=1;o <=j;o++)
printf("%d* ",order[o]);
}
else{printf("%d ",array[i]);
per=i;
i=array[i];
k++;
}
void main()
{
int data[] = {10,9,8,7,6,5,4};
BubbleSort(data,7);
for (int i=0;i<7;i++)
cout<<data[i]<<" ";
cout<<"\n";
}
图示: before_compare|one_turn|two_turn|three_turn|four_turn|five_turn|six_turn 10 10 10 10 10 10 4 9 9 9 9 9 4 10 8 8 8
8 4 9 9 7 7 7 4 8 8 8 6 6 4 7 7 7 7 5 4 6 6 6 6 6 4 5
5 5 5 5 5经由过程上图可以看出,冒泡法形象的描述来,4这个元素就像一个气泡逐渐冒到上面来了。 我们排序的有7个元素,最坏的情况全部倒序,4这个元素要冒上来需要6次。是以,n个元素,最坏的情况,需要移动:1+2+3+ ...+(n-1)=1/2*n(n-1)次。倒序(最糟情况)
第一轮:10,9,8,7->10,9,7,8->10,7,9,8->7,10,9,8(交换3次)
第二轮:7,10,9,8->7,10,8,9->7,8,10,9(交换2次)
第一轮:7,8,10,9->7,8,9,10(交换1次)
循环次数:6次
交换次数:6次
其他:
第一轮:8,10,7,9->8,10,7,9->8,7,10,9->7,8,10,9(交换2次)
第二轮:7,8,10,9->7,8,10,9->7,8,10,9(交换0次)
第一轮:7,8,10,9->7,8,9,10(交换1次)
循环次数:6次
交换次数:3次
上面我们给出了程序段,现在我们分析它:这里,影响我们算法性能的主要部分是循环和交换,显然,次数越多,性能就越差。从上面的程序我们可以看出循环的次数是固定的,为1+2+...+n-1。写成公式就是1/2*(n-1)*n。现在注意,我们给出O方法的定义:
若存在一常量K和起面n0,使当n>=n0时,有f(n)<=K*g(n),则f(n) = O(g(n))。(呵呵,不要说没学好数学呀,关于编程数学是非常重要的!!!)
现在我们来看1/2*(n-1)*n,当K=1/2,n0=1,g(n)=n*n时,1/2*(n-1)*n<=1/2*n*n=K*g(n)。所以f(n)=O(g(n))=O(n*n)。所以我们程序循环的复杂度为O(n*n)。
再看交换。从程序后面所跟的表可以看到,两种情况的循环相同,交换不同。实在交换本身同数据源的有序程度有极大的关系,当数据处于倒序的情况时,交换次数同循环一样(每次循环判断都会交换),复杂度为O(n*n)。当数据为正序,将不会有交换。复杂度为O(0)。乱序时处于中间状态。正是因为这样的原因,我们通常都是经由过程循环次数来对比算法。2.交换法:
交换法的程序最清晰简单,每次用当前的元素一一的同其后的元素比较并交换。
#include <iostream.h>
void ExchangeSort(int* pData,int Count)
{
int iTemp;
for(int i=0;i<Count-1;i++)
{
for(int j=i+1;j<Count;j++)
{
if(pData[j]<pData[i])
{
iTemp = pData[i];
pData[i] = pData[j];
pData[j] = iTemp;
}
}
}
}
void main()
{
int data[] = {10,9,8,7,6,5,4};
ExchangeSort(data,7);
for (int i=0;i<7;i++)
cout<<data[i]<<" ";
cout<<"\n";
} before_compare|one_turn|two_turn|three_turn|four_turn|five_turn|six_turn 10 9 8 7 6 5 4 9 10 10 10 10 10 10 8 8 9
9 9 9 9 7 7 7 8 8 8 8 6 6 6 6 7 7 7 5 5 5 5 5 6 6 4 4
4 4 4 4 5 从上面的算法来看,基本和冒泡法的效率一样。
倒序(最糟情况)
第一轮:10,9,8,7->9,10,8,7->8,10,9,7->7,10,9,8(交换3次)
第二轮:7,10,9,8->7,9,10,8->7,8,10,9(交换2次)
第一轮:7,8,10,9->7,8,9,10(交换1次)
循环次数:6次
交换次数:6次
其他:
第一轮:8,10,7,9->8,10,7,9->7,10,8,9->7,10,8,9(交换1次)
第二轮:7,10,8,9->7,8,10,9->7,8,10,9(交换1次)
第一轮:7,8,10,9->7,8,9,10(交换1次)
循环次数:6次
交换次数:3次
从运行的表格来看,交换几乎和冒泡一样糟。事实确实如此。循环次数和冒泡一样也是1/2*(n-1)*n,所以算法的复杂度仍然是O(n*n)。因为我们无法给出所有的情况,所以只能直接告诉大家他们在交换上面也是一样的蹩脚(在某些情况下稍好,在某些情况下稍差)。3.选择法:
现在我们终于可以看到一面希望:选择法,这种方法提高了一面性能(某些情况下)这种方法类似我们工资的排序习惯:从数据中选择最小的同第一个值交换,在从省下的部分中选择最小的与第二个交换,这样往复下往。
#include <iostream.h>
void SelectSort(int* pData,int Count)
{
int iTemp;
int iPos;
for(int i=0;i<Count-1;i++)
{
iTemp = pData[i];
iPos = i;
for(int j=i+1;j<Count;j++)
{
if(pData[j]<iTemp)
{
iTemp = pData[j];
iPos = j;
}
}
pData[iPos] = pData[i];
pData[i] = iTemp;
}
}
void main()
{
int data[] = {10,9,8,7,6,5,4};
SelectSort(data,7);
for (int i=0;i<7;i++)
cout<<data[i]<<" ";
cout<<"\n";
}该排序法的图示如下; i=0时: iTemp = pData[0]=10;iPos = i=0;
j=1 ;
pData[j]<iTemp ---> pData[1]=9<10;
iTemp=pData[1]=9;
ipos=j=1;
j++=2
j=2;
pData[j]<iTemp----> pData[2]=8<9;
iTemp=pData[2]=8;
ipos=j=2;
j++=3
. . .
j=6;
pData[j]<iTemp----> pData[6]=4<5;
iTemp=pData[6]=4;
ipos=j=6;
j++=7;
pData[6]=Pdata[0];
pData[0]=4;
before_compare one turn two turn three turn
10 4 4 4
9 9 5 5
8 8 8 6
7 7 7 7
6 6 6 8
5 5 9 9
4 10 10 10由上面可以看到选择排序法并没有在一开初就交换数据,而是用第一个数据往和所有的数据比较,如果第一个数据小于第二个数据,那么,先把第二个数据放到一个临时变量里面,同时记载这个较小的数据在待排序的集合中的位置。再用该集合中的下一个数据和我们之前放在临时变量中的数据比较。也就是我们今朝认为最小的数据比较,如果比我们之前选出来的数据小,那么再替换该变量。如果比这个数据大,则继绝用下一个数据来比较。知道所有的数据都比较完为止。到这时,临时变量里面访的就是最小的数据了。我们把这个数据和第一个数据做对换。此时,最小的元素排到了第一位。倒序(最糟情况)
第一轮:10,9,8,7->(iTemp=9)10,9,8,7->(iTemp=8)10,9,8,7->(iTemp=7)7,9,8,10(交换1次)
第二轮:7,9,8,10->7,9,8,10(iTemp=8)->(iTemp=8)7,8,9,10(交换1次)
第一轮:7,8,9,10->(iTemp=9)7,8,9,10(交换0次)
循环次数:6次
交换次数:2次
}
if (!exchange)
{
return;
}
}
}
int main()
{
int a[7]={32,43,22,52,2,10,30};
maopao(a,7);
for(int i=0;i<7;i++)
cout<<a[i]<<" ";
return 0;
}
void main()
{
int data[] = {10,9,8,7,6,5,4};
InsertSort(data,7);
for (int i=0;i<7;i++)
cout<<data[i]<<" ";
cout<<"\n";
}
i=1时:
iTemp=pData[1]=9
ipos=1-1=0;
ipos=0>=0 && iTemp=9<pData[0]=10;
pData[1]=pData[0]=10;
ipos--=0-1=-1;
pData[0]=9; 9-10-8-7-6-5-4
i=2时:
iTemp=pData[2]=8
ipos=2-1=1;
ipos=1>=0 && iTemp=8<pData[1]=10;
pData[2]=pData[1]=10;
ipos--=1-1=0; 9-10-10-7-6-5-4
ipos=0>=0 && iTemp=8<pData[0]=9;
pData[1]=pData[0]=9;
ipos--=0-1=-1;
pData[0]=8; 8-9-10-7-6-5-4
i=3时:
iTemp=pData[3]=7
ipos=3-1=2;
ipos=2>=0 && iTemp=7<pData[2]=10;
pData[3]=pData[2]=10;
ipos--=2-1=1; 8-9-10-10-6-5-4
void insertsort(int a[],int n){
int temp;
for(int i=1;i<n;i++)
{
int j=i;
temp=a[i]; //先把a[i]位置的数据存起来
while(j>0&&temp<a[j-1])
{
a[j]=a[j-1];
j--;
}
a[j]=temp;
}
}
ipos=0>=0 && iTemp=7<pData[0]=8;
pData[1]=pData[0]=8;
ipos--=0-1=-1;
pData[0]=7; 7-8-9-10-6-5-4i=4时:
iTemp=pData[4]=6;
ipos=4-1=3;
ipos=3>=0 && iTemp=6<pData[3]=10;
pData[4]=pData[3]=10;
ipos--=3-1=2; 7-8-9-10-10-5-4
ipos=2>=0 && iTemp=7<pData[2]=9;
pData[3]=pData[2]=9;
ipos--=2-1=1; 7-8-9-9-10-5-4
ipos=1>=0 && iTemp=7<pData[1]=8;
pData[2]=pData[1]=8;
ipos--=1-1=0; 7-8-8-9-10-5-4
ipos=0>=0 && iTemp=7<pData[0]=7;
pData[1]=pData[0]=7;
ipos--=1-1=0;
pDate[0]=6; 6-7-8-9-10-5-4
由上述可知:插进排序是先把集合中的下一个元素抽取出来
放到一个临时变量里面和第一个元素比较。并记载该元素在集合中的位置
如果第二个元素比第一个小,那么第一个元素和第二个元素对调。下一次
再用第三个元素先和变革后的第二个元素比较,如果变革后的第二个元素
小于第三个元素,用第二个元素的值笼罩第三个元素。在从临时变量里面
取出该元素放到第二个元素中往。
倒序(最糟情况)
第一轮:10,9,8,7->9,10,8,7(交换1次)(循环1次)
第二轮:9,10,8,7->8,9,10,7(交换1次)(循环2次)
第一轮:8,9,10,7->7,8,9,10(交换1次)(循环3次)
循环次数:6次
交换次数:3次
其他:
第一轮:8,10,7,9->8,10,7,9(交换0次)(循环1次)
第二轮:8,10,7,9->7,8,10,9(交换1次)(循环2次)
第一轮:7,8,10,9->7,8,9,10(交换1次)(循环1次)
循环次数:4次
交换次数:2次
上面末端的行动分析事实上形成了一种假象,让我们认为这种算法是简单算法中最好的,实在不是,因为其循环次数虽然并不固定,我们仍可以使用O方法。从上面的成绩可以看出,循环的次数f(n)<=1/2*n*(n-1)<=1/2*n*n。所以其复杂度仍为O(n*n)(这里说明一下,实在如果不是为了展示这些简单排序的不同,交换次数仍然可以这样推导)。现在看交换,从外观上看,交换次数是O(n)(推导类似选择法),但我们每次要进行与内层循环相同次数的‘=’操作。一般的一次交换我们需要三次‘=’而这里显然多了一些,所以我们浪费了时间。
最终,我个人认为,在简单排序算法中,选择法是最好的。插进排序
#include <iostream>
using namespace std;
void main()
{
int data[] = {10,9,8,7,6,5,4};
QuickSort(data,7);
for (int i=0;i<7;i++)
cout<<data[i]<<" ";
cout<<"\n";
}
ipos=1>=0 && iTemp=8<pData[1]=9;
pData[2]=pData[1]=9;
ipos--=1-1=0; 8-9-9-10-6-5-4
这里我没有给出行动的分析,因为这个很简单,我们直接来分析算法:首先我们考虑最理想的情况
1.数组的大小是2的幂,这样分下往初终可以被2整除。假设为2的k次方,即k=log2(n)。
2.每次我们选择的值刚好是中间值,这样,数组才可以被等分。
第一层递归,循环n次,第二层循环2*(n/2)......
所以共有n+2(n/2)+4(n/4)+...+n*(n/n) = n+n+n+...+n=k*n=log2(n)*n
所以算法复杂度为O(log2(n)*n)
其他的情况只会比这种情况差,最差的情况是每次选择到的middle都是最小值或最大值,那么他将变成交换法(因为使用了递归,情况更糟)。但是你认为这种情况发生的几率有多大??呵呵,你完全不必担心这个问题。实践证明,大多数的情况,快速排序总是最好的。
如果你担心这个问题,你可以使用堆排序,这是一种稳定的O(log2(n)*n)算法,但是通常情况下速度要慢于快速排序(因为要重组堆)。三、其他排序
1.双向冒泡:
通常的冒泡是单向的,而这里是双向的,也就是说还要进行反向的工作。
代码看起来复杂,仔细理一下就分明了,是一个来回震动的方式。
写这段代码的作者认为这样可以在冒泡的基础上减少一些交换(我不这么认为,也许我错了)。
反正我认为这是一段有趣的代码,值得一看。
#include <iostream.h>
void Bubble2Sort(int* pData,int Count)
{
int iTemp;
int left = 1;
int right =Count -1;
int t;
do
{
//正向的部分
for(int i=right;i>=left;i--)
{
if(pData[i]<pData[i-1])
{
iTemp = pData[i];
pData[i] = pData[i-1];
pData[i-1] = iTemp;
t = i;
}
}
left = t+1;
#include <iostream>
using namespace std;
void maopao(int *list,int n)
{
int i=n,j,temp;
bool exchange;//当数据已经排好时,退出循环
for(i=0;i<n;i++)
{
exchange=false;
for (j=0;j<n-i-1;j++)
{
if (list[j]>list[j+1])
{
temp=list[j];
list[j]=list[j+1];
list[j+1]=temp;
exchange=true;
}
void BubbleSort(int* pData,int Count)
{
int iTemp;
for(int i=1;i<Count;i++)
{
for(int j=Count-1;j>=i;j--)
{
if(pData[j]<pData[j-1])
{
iTemp = pData[j-1];
pData[j-1] = pData[j];
pData[j] = iTemp;
}
}
}
}
//当左边部分有值(left<j),递归左半边
if(left<j)
run(pData,left,j);
//当右边部分有值(right>i),递归右半边
if(right>i)
run(pData,i,right);
}
void QuickSort(int* pData,int Count)
{
run(pData,0,Count-1);
}
void coutstream(int a[],int n){
for(int i=0;i!=n;i++)
cout<<a[i]<<" ";
}
int main()
{
int a[5]={1,6,4,8,4};
insertsort(a,5);//插进排序
coutstream(a,5);//
return 0;
}
二、高级排序算法:
高级排序算法中我们将只介绍这一种,同时也是今朝我所知道(我看过的资料中)的最快的。它的工作看起来仍然象一个二叉树。首先我们选择一个中间值middle程序中我们使用数组中间值,然后把比它小的放在左边,大的放在右边(具体的实现是从双方找,找到一对后交换)。然后对双方分别使用这个过程(最容易的方法——递归)。
//反向的部分
for(i=left;i<right+1;i++)
{
if(pData[i]<pData[i-1])
{
iTemp = pData[i];
pData[i] = pData[i-1];
pData[i-1] = iTemp;
t = i;
}
}
right = t-1;
}while(left<=right);
}
void main()
{
int data[] = {10,9,8,7,6,5,4};
Bubble2Sort(data,7);
for (int i=0;i<7;i++)
cout<<data[i]<<" ";
cout<<"\n";
}快速排序
#include <iostream>
using namespace std;
class QuickSort
{
public:
void quick_sort(int* x,int low,int high)
{
int pivotkey;
if(low <high)
{
pivotkey=partion(x,low,high);
quick_sort(x,low,pivotkey-1);
quick_sort(x,pivotkey+1,high);
}
}
int partion(int* x,int low,int high)
{
int pivotkey;
pivotkey=x[low];
while(low <high)
{
while (low <high&&x[high]>=pivotkey)
--high; //还有while循环只执行这一句
x[low]=x[high];
while (low <high&&x[low] <=pivotkey)
++low; //还有while循环只执行这一句
x[high]=x[low];
}
x[low]=pivotkey;
return low;
}
};
int main()
{
int x[10]={52,49,80,36,14,58,61,97,23,65};
QuickSort qs;
qs.quick_sort(x,0,9);
cout <<"排好序的数字序列为:" <<endl;
for (int i=0;i <10;i++)
{
printf("%d ",x[i]);
}
return 0;
}
2.SHELL排序
这个排序非常复杂,看了程序就知道了。
首先需要一个递减的步长,这里我们使用的是9、5、3、1(最后的步长必需是1)。
工作原理是首先对相隔9-1个元素的所有内容排序,然后再使用一样的方法对相隔5-1个元素的排序以次类推。
#include <iostream.h>
void ShellSort(int* pData,int Count)
{
int step[4];
step[0] = 9;
step[1] = 5;
step[2] = 3;
step[3] = 1;
int iTemp;
int k,s,w;
for(int i=0;i<4;i++)
{
k = step[i];
s = -k;
for(int j=k;j<Count;j++)
{
iTemp = pData[j];
w = j-k;//求上step个元素的下标
if(s ==0)
{
s = -k;
s++;
pData[s] = iTemp;
}
while((iTemp<pData[w]) && (w>=0) && (w<=Count))
{
pData[w+k] = pData[w];
w = w-k;
}
pData[w+k] = iTemp;
}
}
}
void main()
{
int data[] = {10,9,8,7,6,5,4,3,2,1,-10,-1};
ShellSort(data,12);
for (int i=0;i<12;i++)
cout<<data[i]<<" ";
cout<<"\n";
}
呵呵,程序看起来有些头疼。不外也不是很难,把s==0的块往掉就轻松多了,这里是避免使用0步长形成程序异常而写的代码。这个代码我认为很值得一看。这个算法的得名是因为其发明者的名字D.L.SHELL。依照参考资料上的说法:“因为复杂的数学原因避免使用2的幂次步长,它能降低算法效率。”另外算法的复杂度为n的1.2次幂。一样因为非常复杂并“超出本书讨论局限”的原因(我也不知道过程),我们只有成绩了
1.快速排序:
#include <iostream.h>
其他:
第一轮:8,10,7,9->(iTemp=8)8,10,7,9->(iTemp=7)8,10,7,9->(iTemp=7)7,10,8,9(交换1次)
第二轮:7,10,8,9->(iTemp=8)7,10,8,9->(iTemp=8)7,8,10,9(交换1次)
第一轮:7,8,10,9->(iTemp=9)7,8,9,10(交换1次)
循环次数:6次
交换次数:3次
遗憾的是算法需要的循环次数依然是1/2*(n-1)*n。所以算法复杂度为O(n*n)。
我们来看他的交换。因为每次外层循环只产生一次交换(只有一个最小值)。所以f(n)<=n
所以我们有f(n)=O(n)。所以,在数据较乱的时候,可以减少一定的交换次数。4.插进法:
插进法较为复杂,它的基本工作原理是抽出牌,在前面的牌中寻觅相应的位置插进,然后继绝下一张
#include <iostream.h>
void InsertSort(int* pData,int Count)
{
int iTemp;
int iPos;
for(int i=1;i<Count;i++)
{
iTemp = pData[i];
iPos = i-1;
while((iPos>=0) && (iTemp<pData[iPos]))
{
pData[iPos+1] = pData[iPos];
iPos--;
}
pData[iPos+1] = iTemp;
}
}
shell排序的思惟是凭证步长由长到短分组,进行排序,直到步长为1为止,属于插进排序的一种。下面用个例子更好的理解一下 无序数列: 32, 43,56,99,34,8,54,76 1.首先设定gap=n/2=4于是分组 32,34 排序 32,34 43, 8 8, 43 56,54 54,56 99,76 76,99 数列变成 32,8,54,76,34,43,56,99
2.gap=gap/2=2 于是分组 32,54,34,56 排序 32,34,54,56 8,76,43,99 8,43,76,99 于是数列变成 32,8,34,43,54,76,56,99 3.gap=gap/2=1于是分组 32,8,34,43,54,76,56,99 排序 8,32,34,43,54,56,76,99 gap=1结束…… 相应的C语言代码引用K&R C程序设想一书中给出的代码 void shellsort(int v[], int n) { int gap,
i, j, temp; for(gap=n/2;gap>0;gap/=2) //设定步长 for(i=gap;i <n;++i) //在元素间移动为止 for(j=i-gap; j>=0&&v[j]>v[j+gap]; j-=gap){ //比较相距gap的元素,逆序互换 temp=v[j]; v[j]=v[j+gap]; v[j+gap]=temp; } } //帕斯卡恒等式为C(n,k)=C(n-1,k-1)+C(n-1,k)
long fun(long n,long r)
{
if(r<0||n<0)
{
printf("\nError.Exit!");
exit(1);
}
if(r>n) return 0;
if(r==1||r==n-1)//凭证组合定义,我们有C(n,1)=C(n,n-1)=n
return n;
if(r==0||r==n)//凭证组合定义,我们有C(n,0)=C(n,n)=1
return 1;
return fun(n-1,r)+fun(n-1,r-1);//帕斯卡组合公式
}
//选择法对数组排序的函数模板
template <class T>
void selectsort(T arr[],int size)
{
T temp;
int i,j;
for (i=0;i<size-1;i++)
for (j=i+1;j<size;j++)
if (arr[i]>arr[j])
{
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
//冒泡法对数组排序的函数模板
template<class T>
void bubblesort(T *d,int n)
{
int i,j;
T t;
for(i=0;i<n-1;i++)
for(j=0;j<n-i-1;j++)
if(d[j]>d[j+1])
{
t=d[j];
d[j]=d[j+1];
d[j+1]=t;
}
}
//插进法对数组排序的函数模板
template <class T>
void InsertSort(T A[], int n)
{
int i, j;
T temp;
for (i = 1; i < n; i++)
{
temp = A[i];
for (j=i-1; j>=0&&temp<A[j];j--)
A[j+1]=A[j];
A[j+1] = temp;
}
}
//二分查找法的函数模板
template <class T>
int binary_search(T array[], T value, int size)
{
int high = size-1, low = 0, mid;
while (low<=high)
{
mid = (high + low) / 2;
if (value < array[mid])
high = mid - 1;
else if(value>array[mid])
low = mid + 1;
else return mid;
}
return -1;
}
将2~36进制数与10进制数相互转换
//将2~36进制数转换成10进制数
unsigned int OthToDec(char *oth, int base) //base为已知数的进制
{
unsigned int i=0, dec=0;
while (oth[i])
{
dec*=base;
if (oth[i]>='0' && oth[i]<='9')
dec+=oth[i]&15;//dec+=oth[i]-48;
else if (oth[i]>='A' && oth[i]<='Z')
dec+=oth[i]-55;
else if (oth[i]>='a' && oth[i]<='z')
dec+=oth[i]-87;
i++;
}
return dec;
}
//将10进制(无符号)转2~36进制数
char *DecToOth(char *oth, unsigned int dec, int base) //base为要转换的数的进制
{
char ch, *left=oth, *right=oth,num[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
do
{
*right=num[dec%base];
right++;
}while (dec/=base);
*right='\0';
right--;
while (left<right)
{
ch=*left;
*left=*right;
*right=ch;
left++;right--;
}
return oth;
}
void run(int* pData,int left,int right)
{
int i,j;
int middle,iTemp;
i = left;
j = right;
middle = pData[(left+right)/2]; //求中间值
do{
while((pData[i]<middle) && (i<right))//从左扫描大于中值的数
i++;
while((pData[j]>middle) && (j>left))//从右扫描大于中值的数
j--;
if(i<=j)//找到了一对值
{
//交换
iTemp = pData[i];
pData[i] = pData[j];
pData[j] = iTemp;
i++;
j--;
}
}while(i<=j);//如果双方扫描的下标交错,就休止(完成一次)
}
order[n]=i;
printf("\n**************************************\n");
for(i=1;i <=n;i++)
printf("%d ",order[i]);
system("pause");
return 0;
} 输进正整数N,然后是N*N个正整数,表示边权邻接矩阵。
输出求解过程。
/*
Problem : Weighted Bipartite Matching
Algorithm : Hungarian Algorithm
Reference : Douglas B.West,Introduction to Graph Theory,125-129
Author : PC
Date : 2005.2.23
*/
#include <iostream.h>
#include <iomanip.h>
#include <fstream.h>
#include <memory.h>
ifstream fin("input.txt");
#define cin fin
const int max=50;
bool T[max],R[max],visited[max];
int U[max],V[max],gt[max][max],x[max],y[max];
int N;
void output()
{
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
cout<<setw(2)<<gt[i][j]<<' ';
}
if(R[i])cout<<setw(2)<<'R'<<' ';
cout<<endl;
}
for(i=0;i<N;i++)
if(T[i])cout<<setw(2)<<'T'<<' ';
else cout<<setw(2)<<' '<<' ';
cout<<endl;
}
int path(int u)
{
int v;
for(v=0;v<N;v++)
{
if(gt[u][v]==0 && !visited[v])
{
visited[v]=1;
if(y[v]<0 || path(y[v]))
{
x[u]=v;y[v]=u;
R[u]=1;T[v]=0;
return 1;
}else{
T[v]=1;
R[y[v]]=0;
}
}
}
return 0;
}
int main()
{
for(;cin>>N;){
int i,j,ans,sigma,step=0;
for(i=0;i<N;i++)
{
U[i]=V[i]=0;
for(j=0;j<N;j++)
{
cin>>gt[i][j];
if(U[i]<gt[i][j])U[i]=gt[i][j];
}
}
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
gt[i][j]=U[i]-gt[i][j];
}
}
//////////////////////////////////////////////////////////
for(;;)
{
ans=0;
sigma=0;
memset(x,-1,sizeof(x));
memset(y,-1,sizeof(y));
memset(R,0,sizeof(R));
memset(T,0,sizeof(T));
for(i=0;i<N;i++)
{
if(x[i]<0)
{
memset(visited,0,sizeof(visited));
ans+=path(i);
}
for(j=0;j<N;j++)
{
if(sigma<1 || sigma>gt[i][j] && gt[i][j]>0)
sigma=gt[i][j];
}
}
cout<<"step "<<++step<<":\n";
output();
if(ans>=N)
break;
for(i=0;i<N;i++)
{
if(!R[i])
U[i]-=sigma;
if(T[i])
V[i]+=sigma;
for(j=0;j<N;j++)
{
if(T[j])
gt[i][j]+=sigma;
if(!R[i])
gt[i][j]-=sigma;
}
}
}
//////////////////////////////////////////////////////////
ans=0;
cout<<"Result:"<<endl;
for(i=0;i<N;i++)
{
ans+=U[i]+V[i];
for(j=0;j<N;j++)
{
if(x[i]==j && y[j]==i)cout<<setw(2)<<U[i]+V[j]<<' ';
else cout<<setw(2)<<0<<' ';
}
cout<<endl;
}
cout<<"Maximum : "<<ans<<endl;
}
return 0;
}
input.txt:
5
4 1 6 2 3
5 0 3 7 6
2 3 4 5 8
3 4 6 3 4
4 6 5 8 6
5
4 4 4 3 6
1 1 4 3 4
1 4 5 3 5
5 6 4 7 9
5 3 6 8 3
5
7 8 9 8 7
8 7 6 7 6
9 6 5 4 6
8 5 7 6 4
7 6 5 5 5
5
1 2 3 4 5
6 7 8 7 2
1 3 4 4 5
3 6 2 8 7
4 1 3 5 4
/*
Problem : Weighted Bipartite Matching
Algorithm : Hungarian Algorithm
Reference : Douglas B.West,Introduction to Graph Theory,125-129
Author : PC
Date : 2005.2.23
*/
#include <iostream.h>
#include <iomanip.h>
#include <fstream.h>
#include <memory.h>
ifstream fin("input.txt");
#define cin fin
const int max=50;
bool T[max],R[max],visited[max];
int U[max],V[max],gt[max][max],x[max],y[max];
int N;
void output()
{
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
cout<<setw(2)<<gt[i][j]<<' ';
}
if(R[i])cout<<setw(2)<<'R'<<' ';
cout<<endl;
}
for(i=0;i<N;i++)
if(T[i])cout<<setw(2)<<'T'<<' ';
else cout<<setw(2)<<' '<<' ';
cout<<endl;
}
int path(int u)
{
int v;
for(v=0;v<N;v++)
{
if(U[u]+V[v]-gt[u][v]==0 && !visited[v])
{
visited[v]=1;
if(y[v]<0 || path(y[v]))
{
x[u]=v;y[v]=u;
R[u]=1;T[v]=0;
return 1;
}else{
T[v]=1;
R[y[v]]=0;
}
}
}
return 0;
}
int main()
{
int i,j,ans,sigma,step=0;
for(;cin>>N;){
for(i=0;i<N;i++)
{
U[i]=V[i]=0;
for(j=0;j<N;j++)
{
cin>>gt[i][j];
if(U[i]<gt[i][j])U[i]=gt[i][j];
}
}
//////////////////////////////////////////////////////////
for(;;)
{
ans=0;
sigma=0;
memset(x,-1,sizeof(x));
memset(y,-1,sizeof(y));
memset(R,0,sizeof(R));
memset(T,0,sizeof(T));
for(i=0;i<N;i++)
{
if(x[i]<0)
{
memset(visited,0,sizeof(visited));
ans+=path(i);
}
}
for(i=0;i<N;i++)
{
if(!R[i])
for(j=0;j<N;j++)
{
if(!T[j] && (sigma<1 || sigma>U[i]+V[j]-gt[i][j] && U[i]+V[j]-gt[i][j]>0))
sigma=U[i]+V[j]-gt[i][j];
}
}
cout<<"step "<<++step<<":\n";
output();
if(ans>=N)
break;
for(i=0;i<N;i++)
{
if(!R[i])
U[i]-=sigma;
if(T[i])
V[i]+=sigma;
}
}
/////////////////////////////////////////////////////////
ans=0;
cout<<"Result:"<<endl;
for(i=0;i<N;i++)
{
&nb我爱男闺蜜sp; ans+=U[i]+V[x[i]];
for(j=0;j<N;j++)
{
if(x[i]==j && y[j]==i)cout<<setw(2)<<U[i]+V[j]<<' ';
else cout<<setw(2)<<0<<' ';
}
cout<<endl;
}
cout<<"Maximum : "<<ans<<endl;
}
return 0;
}
写函数完成内存的拷贝 void* memcpy( void *dst, const void *src, unsigned int len ) { register char *d; register char *s; if (len == 0) return dst; if ( dst > src ) //考虑笼罩情况 { d = (char *)dst + len - 1; s = (char *)src +
len - 1; while ( len >= 4 ) //循环展开,提高执行效率 { *d-- = *s--; *d-- = *s--; *d-- = *s--; *d-- = *s--; len -= 4; } while ( len-- ) { *d-- = *s--;
} } else if ( dst < src ) { d = (char *)dst; s = (char *)src; while ( len >= 4 ) { *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; len -= 4;
} while ( len-- ) { *d++ = *s++; } } return dst; } 出现次数相当频繁