参考链接:
https://www.cnblogs.com/onepixel/articles/7674659.html
交换俩个数据
void Swap(int *element1, int *element2)
{
int tmp = *element1;
*element1 = *element2;
*element2 = tmp;
}
冒泡排序:从前往后比较相邻俩个数据,如果前面的大于后面的就交换俩个数据,每次将当前比较躺输的最大的数字放到最后。
举例:
代码 :
/*
参数: arr数组指针 n数组元素个数
*/
void BubbleSort(int *arr, int n)
{
assert(arr != NULL && n > 1);
int i, j, flag = 1;//flag==1代表没有排好序
for (i = 0; i < n - 1 && flag; i++)
{
flag = 0;//默认已经排好序,
for (j = 0; j < n - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
Swap(&arr[j], &arr[j + 1]);
flag = 1;
}
}
}
}
选择排序:在给定数列中找到最小元素的下标和首元素位置交换,然后第二次从数组第二个位置开始再找剩下元素中的最小的元素和数组第二个位置交换。
例子:
代码:
void SelectSort(int *arr, int n)
{
assert(NULL != arr && n > 1);
int i, j, CurrentMinIndex;
for (i = 0; i < n; i++)
{
CurrentMinIndex = i;
for (j = i + 1; j < n; j++)
{
if (arr[j] < arr[CurrentMinIndex])
{
CurrentMinIndex = j;
}
}
Swap(&arr[CurrentMinIndex], &arr[i]);
}
}
插入排序:把元素拿出来,在每一轮比较中,把符合要求的元素后移,将拿出来的元素插入到空出来的位置中。
例子:
代码:
void InsertSort(int *arr, int n)
{
assert(NULL != arr && n > 1);
int i, j, SaveIndex,tmp;
for (i = 1; i < n; i++)
{
SaveIndex = i;//保留当前比较的下标
tmp = arr[i];//把值拿出来
for (j = i - 1; j >= 0; j--)
{
if (arr[j] > tmp)//是否比当前的前面的元素小
{
arr[j + 1] = arr[j];//将元素后移
SaveIndex = j;//更新空出来的位置
}
else
{
break;
}
}
if(SaveIndex != i)
arr[SaveIndex] = tmp;//把拿出来的值放到空出来的位置上面。
}
}
希尔排序:(本质上还是一种插入排序)就是按照一定的间隙(步长)将数组分割成多个小部分进行,对分出来的部分进行插入排序,不断的缩小间隙直到排序完成。
例子:
第一次:
第二次:
第三次:
可见希尔排序三次就将数组排好序,有较快的速度。
代码
//希尔排序
void Shell(int *arr, int n, int d)
{
for (int i = d; i < n; ++i)
{
int tmp = arr[i];//拿出来
int j = i - d;
for (; j >= 0 && arr[j] > tmp; j -= d)
{
if (arr[j] > tmp)
arr[j + d] = arr[j];
}
arr[j + d] = tmp;
}
}
void ShellSort(int *arr, int n)
{
int d[] = { 7,5,3,1 };
for (int i = 0; i < 4; i++)
{
Shell(arr, n, d[i]);
}
}
说明这里的增量{7,5,3,1}是所谓的增量因子。关于增量因子的相关知识参考书籍《数据结构》--严蔚敏
快速排序:找到每个元素在即将排好序的数组中的位置,然后再将它前面的数据和后面的数据排好序。就OK了。
举例:
代码:
void QSort(int *arr, int low, int high)
{
if (low >= high)return;
int tmp = arr[low];
int i = low;
int j = high;
while (i < j)
{
while (tmp < arr[j] && i < j)
j--;
arr[i] = arr[j];
if (i < j)
i++;
while (tmp > arr[i] && i < j)
i++;
arr[j] = arr[i];
if (i < j)
j--;
/*while (i < j&&arr[j] >= tmp)j--;
arr[i] = arr[j];
while (i < j&&arr[i] <= tmp)i++;
arr[j] = arr[i];
if (i == j)
{
break;
}*/
}
arr[i] = tmp;
QSort(arr, low, i - 1);
QSort(arr, i + 1, high);
}
堆排序:(实质上是一种选择排序,但是时间复杂度为O(nlogn)) 将数组中的数值初始化为大顶堆,1,将堆顶元素和最后一个元素交换,2,调整堆的顺序。重复1,2直到排序完成。
例子:
一个无序数组 {30,40,60,10,20,50} 转化为树的形式:
初始化为一个大顶堆:1,找到最后一个非叶子节点:公式:最后一个非叶子节点的下标 = 数组长度 /2 - 1;
2,自右向左,自下向上 调整整颗树的关系(使树满足大顶数的定义,所有根节点大于等于其孩子节点。)
初始化完成的大顶堆:
开始排序:
将堆顶元素和最后一个元素交换;(这一步就是,堆开始初始化后交换的第一步)。
重复上面(调整和交换)步骤:
1,调整
2,交换
1,调整:忽视50,60,这里图片给出相关标记。
2,交换
1,调整
2,交换
1,调整
2,交换
排序完毕
代码实现:
//推排序
void adjustBigHeap(int *arr, int i, int length)
{
int tmp = arr[i];
for (int k = i * 2 + 1; k < length; k = k * 2 + 1)
{
if (k + 1 < length&&arr[k] < arr[k + 1])//比较左孩子右孩子那个比较大
{
k++;
}
if (arr[k] > tmp)
{
arr[i] = arr[k];
i = k;
}
else
{
break;
}
}
arr[i] = tmp;
}
void HeapSort(int *arr, int n)
{
//1.构建大顶堆
for (int i = n / 2 - 1; i >= 0; i--)
{
adjustBigHeap(arr, i, n);
}
//2.调整 + 交换
for (int j = n - 1; j > 0; j--)
{
Swap(&arr[0], &arr[j]);
adjustBigHeap(arr, 0, j);//因为交换导致堆的结构错乱,调整。
}
}