冒泡排序
冒泡法排序思路如下:
-
设有n个数,从前向后对相邻两个数比较(共比较n-1次),将小数交换到前面,大数交换到后面。逐次比较,直到将最大的数移到最后为止(此时最大的数在最后,固定下来,目前固定了一个最大数)。
-
剩下前面n-1个数,从前向后,对相邻两个数进行比较(共比较(n-1)-1)=n-2次,将小数交换到前面,大数交换到后面。逐次比较,直到将次大的数移到倒数第二个位置上为止(此时次大的数在倒数第二个位置上,同样被固定了下来,目前固定了两个大数)。
-
余下前面的n-i个数,从前向后,对相邻两个数进行比较(共比较n-i-1次),将小数交换到前面,大数交换到后面。逐次比较,直到将第i+1个大数移到第i+1个位置上为止(也称为大数沉底)。
…
代码如下:
int Partion(int *arr, int low, int high)//找基准
{
int tmp = arr[low];//tmp用来保存第一个元素的值
while (low < high)
{
while (arr[high] > tmp&&low < high)
{
high--;
}
if (arr[high] < tmp)
{
arr[low] = arr[high];
}
else
{
break;
}
while (arr[low] < tmp&&low < high)
{
low++;
}
if (arr[low] > tmp)
{
arr[high] = arr[low];
}
else
{
break;
}
}
arr[low] = tmp;
return low;//low代表找到的基准的位置
}
void BubbleSort(int *arr, int len)
{
for (int i = 0; i < len - 1; i++)//趟数
{
bool swap = false;//swap用来判断是否已经有序(冒泡法的优化)
for (int j = 0; j < len - 1 - i; j++)
{
int tmp = 0;
if (arr[j] > arr[j + 1])
{
tmp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = tmp;
swap = true;
}
}
if (!swap)//swap == false//如果已经有序则跳出循环,不再进行比较。
{
break;
}
}
}
时间复杂度:
无序:O(
)
有序:O(
)
空间复杂度:O( )
稳定性:稳定
选择排序
选择排序思路如下:
从待排序数字开始,后面找到比待排序数字小的数字就发生交换,一直到整个序列遍历完。
代码如下:
void SelectSort(int *arr, int len)
{
for (int i = 0; i < len; i++)
{
for (int j = i + 1; j < len; j++)
{
if (arr[j] < arr[i])
{
int tmp = arr[j];
arr[j] = arr[i];
arr[i] = tmp;
}
}
}
}
时间复杂度:
有序:O(
)
无序:O(
)
空间复杂度:O( )
稳定性:不稳定
直接插入排序
直接插入排序思路如下:
如果有如下一组数字:4,2,6,5,3 首先当我们在最开始的时候,4 是
有序的,然后当拿到数据 2 时,我们需要把 2 放到 4 之前,那也就是
说,我们需要让 4 往后移,然后插入 2,以此类推,我们每次在移动
的时候,是比较一个数字,移动一个数字,并且是从后往前移动。
代码如下:
void InsertSort(int *arr, int len)
{
for (int i = 1; i < len; i++)
{
int tmp = arr[i];
int j = 0;
for (j = i - 1; j >= 0; j--)
{
if (arr[j] > tmp)
{
arr[j + 1] = arr[j];
}
else
{
break;//如果找到要插进去的位置,跳出内层循环
}
}
arr[j + 1] = tmp;
}
}
时间复杂度:
有序:O(n) 越有序 越快
无序:O(
)
空间复杂度:O(1)
稳定性:稳定排序
希尔排序
希尔排序思路如下:
- 采用分组的思想,把一组数字分为若干的小组。
- 而在分组的过程当中,并不是几个几个紧挨着的分组,而是采用特定的
分组方式,每一次都让组内有序。 - 这样排序的好处是,每次排序都是将小的数据尽量往前赶,大的数据尽量往后
赶。 - 在这里面,每一组的数字个数,在每一次分组的时候, 都会缩小增量,比如第一次分组每组 3 个,第二次每组 5 个, 第三次每组 1 个这样去分。(最后一次就直接进行一次插入排序)
- 优点在于,如果不执行前面的分组过程的话,数据的移动次数更多,更复杂,经过排序之后,数据已经越来越有序了,利用直接插入排序特性(越有序越快)
代码如下:
void Shell(int *arr, int len, int gap)//组内进行直接排序
{
for (int i = gap; i < len; i++)
{
int tmp = arr[i];
int j = 0;
for (j = i - gap; j >= 0; j = j - gap)
{
if (arr[j] > tmp)
{
arr[j + gap] = arr[j];
}
else
{
break;
}
}
arr[j + gap] = tmp;
}
}
void ShellSort(int *arr, int len)
{
int drr[] = { 5,3,1 };//每次的分组长度
int lend = sizeof(drr) / sizeof(drr[0]);
for (int i = 0; i < lend; i++)
{
Shell(arr, len, drr[i]);
}
}
时间复杂度:与增量数组有关
空间复杂度: O(1)
稳定性:不稳定
好的增量序列的共同特征:
1、 最后一个增量必须为 1;
2、应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。