思路:
左右相邻的两个数互相比较,大的交换到序列后边,每次遍历排出剩余的最大的数。如下图所示
代码如下:
void BubbleSort(int* a, int n)//n为数组元素个数
{
int i = 0,j = 0;
for (i = 0; i < n; ++i)
{
for (j = i; j < n-i-1; ++j)
{
if (a[j] > a[j + 1])
{
Swap(&a[j], &a[j + 1]);
}
}
}
}
时间复杂度:O()
空间复杂度:O(1)
思路:
认为数组中的第一个元素已经有序
之后(n-1)个元素依次与前面已经排好的元素经行比较
如果待排序元素obj小于已排序好的最后一个元素last,则交换obj和last
obj和新的last比较,直到找到最后一个last小于自己
重复2-4
思路图如下:
代码如下:
void InsertSort(int* a, int n)//插入排序
{
for (int i = 0; i < n - 1; i++)
{
int end = i;
int tmp = a[end + 1];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + 1] = a[end];
end--;
}
else
{
break;
}
}
a[end + 1] = tmp;
}
}
时间复杂度:最坏情况O()(倒序),最好情况O(n)
空间复杂度:O(1)
思路:希尔排序是插入排序的优化版本
1.将待排序数组等分为gap组,每组有n/gap个元素
2.分别对每组进行插入排序
3.缩小gap,重复1和2
4.重复3,直到gap=1
思路导图如下:
代码如下:
void Shellsort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1;
for (int i = 0; i < n-gap; i++)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + gap] = a[end];
a[end] = tmp;
end -= gap;
}
else
break;
}
}
}
}
时间复杂度:最好情况O(),最坏情况O()
空间复杂度:O(1)
思路:每次遍历待排序数组时,选出最大值和最小值,最后将其与数组首尾元素互换。
思路导图如下:
代码如下:
void SelectSorrt(int* a, int n)//选择排序
{
int begin = 0, end = n - 1;
while (begin < end)
{
int mini = begin, maxi = begin;
for (int i = begin + 1; i <= end; ++i)
{
if (a[i] < a[mini])
{
mini = i;
}
if (a[i] > a[maxi])
{
maxi = i;
}
}
Swap(&a[begin], &a[mini]);
if (maxi == begin)
maxi = mini;
Swap(&a[end], &a[maxi]);
++begin;
--end;
}
}
时间复杂度:O()
空间复杂度:O(1)
思路:是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是
通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。
代码如下:
void Adjustdown(HeapDatatype* a, int n, int parent)
//建大堆
{
int child = parent * 2 + 1;
while (child < n)
{
// 确认child指向大的那个孩子
if (child + 1 < n && a[child + 1] > a[child])
{
child++;
}
// 1、孩子大于父亲,交换,继续向下调整
// 2、孩子小于父亲,则调整结束
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
break;
}
}
void Heapsort(int* array, int n)
{
assert(array);
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
{
Adjustdown(array, n, i);
}
for (int i = 0; i < n - 1; i++)
{
Swap(&array[0], &array[n - 1 - i]);
Adjustdown(array, n - 1 - i, 0);
}
}
时间复杂度:O(nlogn)
空间复杂度:O(1)
思路:
1、选出一个key,一般是最左边或是最右边的。
2、定义一个begin和一个end,begin从左向右走,end从右向左走。(需要注意的是:若选择最左边的数据作为key,则需要end先走;若选择最右边的数据作为key,则需要bengin先走)。
3、在走的过程中,若end遇到小于key的数,则停下,begin开始走,直到begin遇到一个大于key的数时,将begin和right的内容交换,end再次开始走,如此进行下去,直到begin和end最终相遇,此时将相遇点的内容与key交换即可。(选取最左边的值作为key)
4.此时key的左边都是小于key的数,key的右边都是大于key的数
5.将key的左序列和右序列再次进行这种单趟排序,如此反复操作下去,直到左右序列只有一个数据,或是左右序列不存在时,便停止操作,此时此部分已有序
int PartSort1(int* a, int begin, int end)//Hoare法
{
int mid = GetMidIndex(a, begin, end);
int left = begin;
int right = end;
int keyi = left;
Swap(&a[left], &a[right]);
while (left < right)
{
while (lefta[keyi])//先走右边,找小
{
--right;
}
while (left < right && a[left] < a[keyi])
{
++left;
}
Swap(&a[left], &a[right]);
}
Swap(&a[left], &a[keyi]);
keyi = left;
return keyi;
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
return;
if ((right - left + 1) < 15)
{
// 小区间用直接插入替代,减少递归调用次数
InsertSort(a + left, right - left + 1);
}
else
{
int keyi = PartSort2(a, left, right);
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}
}
思路:
1.选出一个数据(一般是最左边或是最右边的)存放在key变量中,在该数据位置形成一个坑
2、还是定义一个L和一个R,L从左向右走,R从右向左走。(若在最左边挖坑,则需要R先走;若在最右边挖坑,则需要L先走)
后面的思路与hoare版本思路类似
int PartSort2(int* a, int begin, int end)//挖坑法
{
int left = begin;
int right = end;
int key = a[left];
int hole = left;
while (left < right)
{
// 右边找小,填到左边坑里面
while (left < right && a[right] >= key)
{
--right;
}
a[hole] = a[right];
hole = right;
// 左边找大,填到右边坑里面
while (left < right && a[left] <= key)
{
++left;
}
a[hole] = a[left];
hole = left;
}
a[hole] = key;
return hole;
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
return;
if ((right - left + 1) < 15)
{
// 小区间用直接插入替代,减少递归调用次数
InsertSort(a + left, right - left + 1);
}
else
{
int keyi = PartSort2(a, left, right);
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}
}
思路:
1、选出一个key,一般是最左边或是最右边的。
2、起始时,prev指针指向序列开头,cur指针指向prev+1。
3、若cur指向的内容小于key,则prev先向后移动一位,然后交换prev和cur指针指向的内容,然后cur指针++;若cur指向的内容大于key,则cur指针直接++。如此进行下去,直到cur到达end位置,此时将key和++prev指针指向的内容交换即可。
经过一次单趟排序,最终也能使得key左边的数据全部都小于key,key右边的数据全部都大于key。
int PartSort3(int* a, int begin, int end)
{
int keyi = begin;
int prev = begin, cur = begin + 1;
while (cur <= end)
{
// 找到比key小的值时,跟++prev位置交换,小的往前翻,大的往后翻
if(a[cur] < a[keyi] && ++prev != cur)
Swap(&a[prev], &a[cur]);
++cur;
}
Swap(&a[prev], &a[keyi]);
keyi = prev;
return keyi;
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
return;
if ((right - left + 1) < 15)
{
// 小区间用直接插入替代,减少递归调用次数
InsertSort(a + left, right - left + 1);
}
else
{
int keyi = PartSort3(a, left, right);
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}
}