一、插入排序
1、直接插入排序
void InsertSort(int arr[], int size)
{
if (arr == NULL || size <= 0)
return;
for (int i =0; i < size-1; i++)
{
int end = i;//一个有序序列的结尾
int tmp = arr[i+1];
while (end >= 0 && arr[end]>tmp)
{
arr[end + 1] = arr[end];
end--;
}
arr[end + 1] = tmp;
}
}
有序或接近有序的情况下非常快
2、希尔排序
其实是插入排序的优化,在直接插入排序在有序或接近有序的时候是最快的
void ShellSort(int arr[], int size)
{
if (arr == NULL || size <= 0)
return;
int gap = size;
while (gap > 1)
{
gap = gap / 3 + 1;//保证当gap《3时,gap的值转换为1
for (int i = 0; i < size - gap; ++i)
{
int end = i;
int tmp = arr[end + gap];
while (end >= 0 && arr[end]>tmp)//几个不同的区间同时控制,而不是控制完一个区间,再控制下一个区间
{
arr[end + gap] = arr[end];
end -= gap;
}
arr[end + gap] = tmp;
}
}
}
前面几次的gap都是预排序,只是为了最后一次gap==1时候的排序
效果最好:正好是逆序
效果最坏:本身就接近有序的情况(比直接插入排序要坏)
二、选择排序
1、.选择排序
选择排序其实是一个比较鸡肋的排序,最好和最坏的情况下时间复杂度都是O(N^2)(n+(n-1)+(n-2)+...+1)
(1)未优化
void SelectSort(int* arr, int size)
{
if (arr == NULL&&size <= 0)
return;
for (int i = 0; i < size; i++)
{
int minIndex = i;
for (int j = i + 1; j < size; j++)
{
if (arr[j] < arr[minIndex])
minIndex = j;
}
std::swap(arr[minIndex], arr[i]);
}
}
(2)优化:每一趟都可以选出最大值和最小值,然后进行交换
void SelectSort_OP(int* arr, int size)
{
if (arr == NULL || size <= 0)
return;
int left = 0;
int right = size - 1;
while (left < right)
{
for (int i = left; i <= right; i++)
{
if (arr[i] < arr[left])
{
std::swap(arr[i], arr[left]);
}
if (arr[i] > arr[right])
{
std::swap(arr[i], arr[right]);
}
}
left++;
right--;
}
}
2、堆排序
void AdjustDown(int arr[],int size, int parent)
{
int child = parent * 2 + 1;
while (child < size)
{
if ((child + 1 < size)&&(arr[child + 1] > arr[child]))
{
child++;
}
if (arr[child]>arr[parent])
{
std::swap(arr[child], arr[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void HeapSort(int* arr, int size)
{
if (arr == NULL || size <= 0)
return;
for (int i = (size - 2) / 2;i>=0; i--)//从后向前建堆
{
AdjustDown(arr, size, i);
}
for (int i = 0; i < size; i++)
{
std::swap(arr[0], arr[size-1-i]);//最后一个位置的下标
AdjustDown(arr, size - 1 - i, 0);//数据的个数,注意这里是size-1-i,因为已经发生了一次交换
}
}
三、交换排序
1.冒泡排序
(1)未优化
void BubbleSort(int arr[], int size)
{
if (arr == NULL || size <= 0)
return;
for (int i = 0; i < size - 1; i++)
{
for (int j = 0; j < size - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
std::swap(arr[j], arr[j + 1]);
}
}
}
(2)优化一:设置标志位,判断是否发生交换
void BubbleSort_OP1(int arr[], int size)
{
if (arr == NULL || size <= 0)
return;
for (int i = 0; i < size - 1; i++)
{
int flag = -1;
for (int j = 0; j < size - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
std::swap(arr[j], arr[j + 1]);
flag = j;
}
}
if (flag == -1)
break;
}
}
(2)优化二:记录最后一次发生交换的位置
void BubbleSort_OP2(int arr[], int size)
{
if (arr == NULL || size <= 0)
return;
int lastSwapPos = size - 1;//最后一个发生交换的位置,下面由这句话控制i < end,<span style="color:#ff0000;">也可以记忆为大于lastSwapPos的坐标的值都是有序的</span>
while (lastSwapPos > 0)
{
int end = lastSwapPos;
for (int i = 0; i < end; i++)//注意这里是<不是<=,因为下面是arr[i]和arr[i+1]比较
{
if (arr[i] > arr[i + 1])
{
lastSwapPos = i;
std::swap(arr[i], arr[i + 1]);
}
}
if (lastSwapPos == end)
{
break;
}
}
}
(3)优化三:
其实是第二种方法的一种优化,遍历两次,从左往右遍历,记录最后一个上浮的位置right,该坐标以上的位置都是有序的;从右往左遍历,记录最后一个下沉的位置left,
下一次直接在[left,right]这个区间中遍历即可
void BubbleSort_OP3(int arr[], int size)
{
if (arr == NULL || size <= 0)
return;
int left = 0;
int right = size - 1;
while (left < right)
{
int lastSwapPos = right;
for (int i = 0; i < lastSwapPos; i++)
{
if (arr[i] > arr[i + 1])
{
right = i;
std::swap(arr[i], arr[i + 1]);
}
}
if (lastSwapPos == right)
break;
lastSwapPos = left;
for (int i = right; i > lastSwapPos; i--)
{
if (arr[i] < arr[i - 1])
{
left = i;
std::swap(arr[i], arr[i - 1]);
}
}
if (lastSwapPos == left)
break;
}
}
2、快速排序
有序写法比较多所以单独写为一篇博客