直接插入排序:
像打扑克牌一样,将要插入的元素与之前排好序的元素比较
<1>找出合适的插入位置,将其他元素向后搬移
<2>将要插入的元素插入
代码实现:
void insertSort(int* array, int size)
{
for (int i = 1; i < size; ++i)
{
int key = array[i];
int end = i - 1;
while (key < array[end] && end >= 0)
{
array[end + 1] = array[end];
end--;
}
array[end + 1] = key;
}
}
希尔排序:
希尔排序是对直接插入排序的优化,又被称为缩小增量排序法
使用的也是插入排序的思想,但是gap>1时都是预排序
适用于大量且无序的数据,使用分组的方法来减少元素个数,对每一组进行排序
<1>将相同间隔的元素放在一组
<2>逐个取元素,比较的时候跳过gap个元素
<3>插入的时候也是插入到这个元素的gap位置后
<4>大佬计算得出的gap取值最好是gap/3+1,跳出条件与直接插入排序的gap>0不同,应该是gap>1
代码实现:
void shellSort(int* array, int size)
{
int gap = size;
while (gap > 1)
{
gap = gap / 3 + 1;
for (int i = gap; i < size; ++i)
{
int key = array[i];
int end = i - gap;
while (key < array[end] && end >= 0)
{
array[end + gap] = array[end];
end -= gap;
}
array[end + gap] = key;
}
//gap--;
}
}
选择排序:
首先找出最大元素的下标,然后与最后一个元素交换,中间跳过元素所以是不稳定排序
缺陷是进行重复比较
<1>已经遍历过多少趟就代表j可以选取的元素少多少个,所以j取值小于size-i
<2>同理,最后把选取出来的元素放的位置的下标也是size-1的基础上减去i
代码实现:
void swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void selectSort(int* array, int size)
{
for (int i = 0; i < size - 1; ++i)
{
int maxPos = 0;
for (int j = 1; j < size-i; ++j)
{
if (array[j]>array[maxPos])
{
maxPos = j;
}
}
if (maxPos != size - i - 1)
{
swap(&array[maxPos], &array[size - i - 1]);
}
}
}
前后同时选择排序:
对选择的排序的简单优化,理论上可以使排序更快
一前一后的进行选择元素,选出最大的元素和end位置元素交换,选出最小的元素和begin位置元素交换
<1>如果找出的最大元素的下标已经在end位置就不用交换
<2>如果找出的最小元素的下标已经在begin位置就不用交换
<2>小元素如果刚好在end的位置,maxpos和end交换过之后,minpos的位置变到maxpos位置
代码实现:
void selectSort2(int* array, int size)
{
for (int i = 0; i < size - 1; ++i)
{
int begin = 0;
int end = size - 1;
while (begin < end)
{
int maxPos = begin;
int minPos = begin;
int index = begin + 1;
while (index <= end)
{
if (array[index]>array[maxPos])
{
maxPos = index;
}
if (array[index] < array[minPos])
{
minPos = index;
}
++index;
}
if (maxPos != end)
{
swap(&array[maxPos], &array[end]);
}
//小元素如果刚好在end的位置,maxpos和end交换过之后,minpos的位置变到maxpos位置
if (minPos == end)
{
minPos = maxPos;
}
if (minPos != begin)
{
swap(&array[minPos], &array[begin]);
}
begin++;
end--;
}
}
}
堆排:
void HeapAdjust(int* array, int size, int parent)
{
int child = parent * 2 + 1;
while (child < size)
{
// 找左右孩子中较大的孩子
if (child + 1 < size && array[child + 1] > array[child])
{
child += 1;
}
if (array[child] > array[parent])
{
Swap(&array[child], &array[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
return;
}
}
}
void HeapSort(int* array, int size)
{
//建堆
int root = ((size - 1) >> 1);
for (root; root >= 0; --root)
{
HeapAdjust(array, size, root);
}
//排序
int end = size - 1;
while (end != 0)
{
swap(&array[0], &array[end]);
HeapAdjust(array, end, 0);
end--;
}
}
冒泡排序:
void BubbleSort(int* array, int size)
{
int i = 0;
int j = 0;
for (i; i < size; ++i)
{
for (j=size-1; j >i ; --j)
{
if (array[j - 1] > array[j])
{
swap(&array[j - 1], &array[j]);
}
}
}
}
快速排序基准值分割的三种方法:
方法一:
<1>设定一个基准值,为了方便起见,设为最后一个元素
<2>采用两个指针(元素下标)的方式,从前往后找比基准值大的元素,从后往前找比基准值小的元素
<3>找到之后将两个位置的元素互换
<4>极端情况是一开始找的基准值就是整个数据中最大的或者最小的,所以begin与end不相等时交换
<5>基准值最大的情况,begin与end相等,基准值最小的情况,end与begin相等
<6>最后放置基准值时必须与right-1位置的元素交换,不能与K交换,与K交换的话,righ-1位置的元素不变
int partion1(int* array, int left, int right)
{
int key = array[right - 1];
int begin = left;
int end = right-1;
while (begin < end)
{
while (array[begin] <= key && begin < end)
{
begin++;
}
while (array[end] >= key && begin < end)
{
end--;
}
if (begin != end)
{
swap(&array[begin], &array[end]);
}
}
//放好基准值
//这里必须和right-1比较,因为end是会动的
if (begin != right-1)
{
swap(&array[begin], &array[right-1]);
}
return begin;
}
方法二:
<1>与方法一类似,一个从前往后找比基准值大的元素,另一个从后往前找比基准值小的元素
<2>begin<end表示还有元素,如果不满足这个条件说明找完整个数据也没找到
<3>找到比基准值大的元素就填充到end位置,然后end自减
<4>找到比基准值小的元素就填充到begin位置,然后begin自增
<5>最后把基准值插入到begin或者end的位置都行,因为那时begin和end相等
int partion2(int* array, int left, int right)
{
int key = array[right - 1];
int begin= left;
int end = right - 1;
while (begin < end)
{
//从前往后找比基准值大的元素
while (array[begin] < key && begin < end)
{
begin++;
}
//填充最后的end位置
if (begin<end)
{
array[end] = array[begin];
end--;
}
//从后往前找比基准值小的元素
while (array[end] > key && begin < end)
{
end--;
}
if (begin < end)
{
array[begin] = array[end];
begin++;
}
}
array[begin] = key;
return begin;
}
方法三:
<1>和方法一类似,不过这个两个都从前开始,还是先设置基准值,最后一个元素
<2>将cur放在第一个元素的位置,pre放在cur的前一个位置
<3>cur标记的元素如果比基准值大,pre不动,cur继续往后走
<4>cur标记的元素如果比基准值小,pre走一步然后看是否与cur相等
<5>相等话什么也不做,cur继续往后走,如果不相等,交换pre和cur位置的元素
<6>最后将基准值放入pre+1位置
int partion3(int* array, int left, int right)
{
int cur = left;
int pre = cur - 1;
int key = array[right - 1];
while (cur < right)
{
//cur标记的元素比基准值小,并且pre走一步不和cur相同,说明中间的都比基准值大,交换
//cur标记的元素比基准值大,cur继续走,但是pre是不动的,pre走和cur标记的比基准值小同步
if (array[cur] < key && ++pre != cur)
{
swap(&array[pre], &array[cur]);
}
cur++;
}
//交换的是基准值位置的值,不是和key保存的值交换
if ((pre + 1) != right)
{
swap(&array[pre + 1], &array[right - 1]);
}
return pre + 1;
}
快速排序的框架:
void QuickSort(int* array, int left,int right)
{
//元素个数最少一个
if (right - left > 1)
{
//int div = partion1(array, left, right);
//int div = partion2(array, left, right);
int div = partion3(array, left, right);
QuickSort(array, left, div);
QuickSort(array, div + 1, right);
}
}
主函数:
int main()
{
int a[] = { 0, 1, 9, 5, 3, 8, 6, 7, 25 };
//insertSort(a,sizeof(a)/sizeof(a[0]));
//shellSort(a, sizeof(a) / sizeof(a[0]));
//selectSort(a, sizeof(a) / sizeof(a[0]));
//selectSort2(a, sizeof(a) / sizeof(a[0]));
//BubbleSort(a, sizeof(a) / sizeof(a[0]));
QuickSort(a, 0, sizeof(a) / sizeof(a[0]));
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
printf("%d ", a[i]);
}
printf("\n");
system("pause");
return 0;
}
代码运行测试图: