排序(中)—选择、冒泡
选择排序
简单来说就是众神归位法,每一趟排序都会选出一个最大的和一个最小的数据,并放在该放的位置上。
由小到大进行排序:
- 遍历整个数据,选出最大的数据(下标),与最后一个下标的数据进行交换,数组的大小减一。
- 遍历剩余的数据,选出最大的数据(下标),与最后一个剩余数据的最后一个下标的数据进行交换。
- 直到剩余的数据中只有一个元素,排序完成。
- 时间复杂度都是O(n^2)
流程图:
代码:
//选择排序
void SelectSort(int arr[], int size)
{
int maxIndex = 0;
int endIndex = 0;
int i = 0;
for (endIndex = size-1; endIndex>=0; endIndex--)//每次交换之后都会让数据的元素个数减少一个
{
for (i = 0,maxIndex = 0; i<=endIndex; i++)
{
if (arr[i] > arr[maxIndex])//让maxIndex始终指向最大的数据
{
maxIndex = i;
}
}
//已经找到,进行交换
int tmp = arr[endIndex];
arr[endIndex] = arr[maxIndex];
arr[maxIndex] = tmp;
}
}
上面的代码是一次性找出一个最大的数,每次选出最大的数都需要n次,但是我们可以简单的修改一下代码让其循环次数更小,思想是每次找出一个最大的和一个最小的,将最大的放在后面,将最小的放在最前面,这样数据元素的个数每次都要减少2.
代码:
//选择排序升级版
void SelectSortPlus(int arr[], int size)
{
int maxIndex = 0;//代表最大数的下标
int minIndex = 0;//最小数的下标
int startIndex = 0;//每次循环的开始下标
int endIndex = size - 1;//每次循环的截止下标
int i = 0;
for (;startIndex <= endIndex; startIndex++,endIndex--)
{
for (i=startIndex,maxIndex = startIndex, minIndex = startIndex; i<=endIndex; i++)
{
if (arr[i] > arr[maxIndex])
{
maxIndex = i;
}
else if (arr[i] < arr[minIndex])
{
minIndex = i;
}
}
//交换的时候如果某一次最小的值的下标在循环的截止下标
//那么此时就应该先将最小的交换至开始循环的位置
if(minIndex == endIndex)
{
Swap(arr+minIndex, arr+startIndex);//Swap的实现就不用实现了吧
Swap(arr+maxIndex, arr+endIndex);
}
else//否则就应该先交换最大的值
{
Swap(arr+maxIndex, arr+endIndex);
Swap(arr+minIndex, arr+startIndex);
}
}
}
这样大大减少了总的循环次数
冒泡排序
世界上最简单的排序算法,思路是从一组数据的第一个数据开始,将较大(或者较小)的数据一步一步推向最后一个位置
- 从第一个数据开始进行比较,与其后面的进行比较,如果大于其后面的数,那就进行交换。
- 向后偏移,从第二个数据开始,因为刚才的比较和交换,现在第二个数是前两个数种最大的,然后再将第二个数与第三个数进行比较,然后同上。
- 当排到倒数第二个数的时候,就说明已经将整个数据种最大的数推到了最后一个位置。
- 然后进行第二次排序,选出倒数第二个,倒数第三个……
- 每一趟循环之后,下一次循环可以排到上次排过的数的前面,这样每一趟循环,下一趟就会少次比较。
- 时间复杂度:
- 最好O(n)
- 最坏O(n^2)
代码:
//冒泡排序
void BubbleSort(int arr[], int size)
{
int endIndex = 0;
int i = 0;
for (endIndex=size-1; endIndex>=0; endIndex--)
{
for (i=0; i < endIndex; i++)
{
if (arr[i] > arr[i+1])
{
int tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}
}
}
}