我们都知道冒泡排序的串行算法的实现,非常简单,两个for循环即可实现,那么并行算法又如何实现呢?
先介绍一下算法思想。
(1)串行算法思想:从左至右依次比较相邻的两个数据,如果左边的数比右边的数大,则交换,这样经过一轮变换后,最大的数据就会移到最右边;然后第二轮只需比较剩余的n-1个数即可,找到次最大的数据;依次类推,直到将这n个数据排好序。
下面是串行冒泡排序算法的核心代码:
for(i=0;i<n-1;i++) //n-1轮
{
for(j=0;j<n-i-1;j++)
{
if(array[j]>array[j+1])
{
tmp=array[j];
array[j]=array[j+1];
array[j+1]=tmp;
}
}
}
(2)并行算法思想:并行算法可以使用奇偶排序是冒泡排序的并行化版本,其思想就是将冒泡排序的每轮操作分解成奇数位和偶数位上的比较、交换,且互不干扰,所以可以并行化。
//#include"stdafx.h"
#include<stdio.h>
#include<malloc.h>
#include<windows.h>
int* array;
bool flag=false;
void Exchange(int* j) //比较并交换相邻元素
{
int b;
int k=*((int* )j);
if(array[k]>array[k+1])
{
b=array[k];
array[k]=array[k+1];
array[k+1]=b;
flag=true;
}
}
void Parallel_BubbleSort(int length) //并行冒泡排序主体
{
int i,j;
int *tag=(int* )malloc(sizeof(int)*length);
for(i=0;i<length;i++)
tag[i]=i;
HANDLE* h=(HANDLE* )malloc(sizeof(HANDLE)*(length/2));
for(i=0;i<length;i++)
{
if(i%2==0) //比较偶数位
{
for(j=0;j<length-1;j+=2) //每循环一次,就创建一个交换线程
{
//创建线程函数
h[j/2]=CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)Exchange,
&tag[j], //不能直接传j,j值会改变
0,
NULL);
printf("创建偶数线程\n");
}
WaitForMultipleObjects((length-1)/2,h,TRUE,INFINITE);
}
else //比较奇数位
{
for(j=1;j<length-1;j+=2)
{
h[(j-1)/2]=CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)Exchange,
&tag[j],
0,
NULL);
printf("创建奇数线程\n");
}
WaitForMultipleObjects(length/2,h,TRUE,INFINITE);
if(!flag) //当一次偶一次奇之后,才能跳出
break;
flag=false;
}
}
}
void main()
{
int i,length;
printf("请输入数组长度:");
scanf("%d",&length);
if(length<0)
printf("输入错误!");
else
{
array=(int* )malloc(sizeof(int)*length); //创建动态数组
printf("请输入数组的值:");
for(i=0;i<length;i++)
{
scanf("%d",&array[i]);
}
Parallel_BubbleSort(length);
for(i=0;i<length;i++)
printf("%d ",array[i]);
printf("\n");
}
}
上述代码,为了提高算法效率,增加了一个标志位flag,当最后数组数据已经排好序,就跳出循环,而非循环最大的次数。
在两个算法前后加上clock()计时函数,比较运行时间发现:并行的奇偶排序算法所花费的时间比串行算法还要多,因为它创建线程非常频繁,所消耗的时间相对来说比较大。