今天在读公司的平台代码的时候发现了一处排序的地方,令我意外的是居然还在用最原始的时间复杂度为的 O(n的平方) 排序方式。
刚看到那些代码无法分清究竟是 交换排序 还是 冒泡排序,记得有一次面试的时候让写冒泡排序呢结果写成交换排序了,当时怎么想也想不起来惭愧,
回来后看了一眼才恍然大悟。其实这两个都是课堂上学过的。这里有必要再分析下它们的区别:
首先说冒泡排序:
将被排序的记录数组R[1..n]垂直排列,每个记录 R[i] 看作是 重量 为R[i].key的气泡。根据轻气泡不能在重气泡之下的原则,从下往上扫数组R:
凡扫描到违反本原则的轻气泡,就使其向上"飘浮"。如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下(所谓 清者为天 浊者为地 )为止
code示例如下:(从小到大)
void BubbleSort(int *vInt, size_t size )
{
int temp;
size_t i,j;
for (i = 0; i < size; i++)
{
for (j = size - 1; j > i; j--)
{
if (vInt[j] < vInt[j-1])
{
temp = vInt[j-1];
vInt[j-1] = vInt[j];
vInt[j] = temp;
}
}
}
}
然后就是交换排序:
交换法的程序最清晰简单,每次用当前的元素一一的同其后的元素比较并交换。 (从小到大)
void ExchangeSort(int* pData,size_t Count)
{
int iTemp;
size_t i,j;
for(i=0;i<Count-1;i++)
{
for(j=i+1;j<Count;j++)
{
if(pData[j]<pData[i])
{
iTemp = pData[i];
pData[i] = pData[j];
pData[j] = iTemp;
}
}
}
}
上面的两种排序可以用如下验证:
int main(void)
{
int i;
int array[] = {12,18,81,-14,-1,0,33,38,46};
int len = sizeof(array)/sizeof(int);
printf("len is %d\n",len);
for(i = 0;i< len;i ++)
printf("%d ",array[i]);
printf("\n");
BubbleSort(array,len);
for(i = 0;i < len; i ++)
printf("%d ",array[i]);
printf("\n\n");
return 0;
}
其实严格来说冒泡排序也属于交换排序的一种,它们的时间复杂度都是 O(n的平方) 。它们的不同点:
冒泡排序在 内部的一个循环 比较连续的2个元素,如果不等则交换。
交换排序是 在内部的一个循环中把每个元素跟外部循环的元素相比较 ,如果不等则交换。
代码优化
int i = 0;
SKY_SERVICE_INFO *pServiceInfo[MAX_TOTAL_PROGRAM_NUM] = {NULL};
for (i = 0; i < iProgramTotal; i++)
{
pServiceInfo[i] = sk_mem_malloc(sizeof(SKY_SERVICE_INFO));
memset(pServiceInfo[i], 0, sizeof(SKY_SERVICE_INFO));
sky_DM_Service_Get(channel[i], pServiceInfo[i]);
}
if (tpye == SORT_SERVICE_ID)
{
sk_char_service_id(pServiceInfo, iProgramTotal);
for (i = 0; i < iProgramTotal; i++)
{
channel[i] = pServiceInfo[i]->id;
}
SendMessage(hWndGrid[PROGRAL_LIST_GRID], LMSG_SETCONTROLDATA, 0, iProgramTotal);
}
for (i = 0; i < iProgramTotal; i++)
{
if (pServiceInfo[i] != NULL)
{
sk_mem_free(pServiceInfo[i]);
pServiceInfo[i] = NULL;
}
}
上面代码的目的是把指针数组(一个数组,数组的每个元素是指向 SKY_SERVICE_INFO 结构体类型的指针)pServiceInfo 所指向的结构体 按照结构体某个成员来排列,
最后 pServiceInfo 是无用的,有用的仅仅是channel数组(pServiceInfo 通过一定规则排序之后ID与channel对应)
再看下 sk_char_service_id 函数
void sk_char_service_id(SKY_SERVICE_INFO *service_info[], int n)//沉底法则
{
int i = 0, j = 0, iFlag = 0;
SKY_SERVICE_INFO tmpe_service_info = {0};
for (i = 0; i < n - 1; i++)
{
iFlag = 1;
memset(&tmpe_service_info, 0, sizeof(SKY_SERVICE_INFO));
for (j = 0; j < n - i - 1; j++)
{
if (str_order_service_id(service_info[j]->svid, service_info[j+1]->svid) == 0)
{
memcpy(&tmpe_service_info, service_info[j], sizeof(SKY_SERVICE_INFO));
memcpy(service_info[j], service_info[j+1], sizeof(SKY_SERVICE_INFO));
memcpy(service_info[j+1], &tmpe_service_info, sizeof(SKY_SERVICE_INFO));
iFlag = 0;
}
}
if (1 == iFlag)
{
break;
}
}
}
这里用的只是简单的冒泡排序,而且if里面的交换也有很大优化空间
3次 memcpy 的过程仅仅是让指针 service_info[j] 和指针 service_info[j+1] 指向的内容一致,这3次memcpy可能需要大量的cpu周期,如果采用别的办法,
比如说交换 service_info[j] 和 service_info[j+1] 的指针值那么则可以大大减少cpu周期,采用这种方式之后 sk_char_service_id 函数如下所示:
void sk_char_service_id(SKY_SERVICE_INFO *service_info[], int n)//沉底法则
{
int i = 0, j = 0, iFlag = 0;
SKY_SERVICE_INFO *ptmp_service_info = NULL;
for (i = 0; i < n - 1; i++)
{
iFlag = 1;
for (j = 0; j < n - i - 1; j++)
{
if (str_order_service_id(service_info[j]->svid, service_info[j+1]->svid) == 0)
{
ptmp_service_info = service_info[j];
service_info[j] = service_info[j+1];
service_info[j+1] = ptmp_service_info;
iFlag = 0;
}
}
if (1 == iFlag)
{
break;
}
}
}