算法
1.冒泡排序
//冒泡排序
//时间复杂度O(n^2)
//空间复杂度O(1)
//稳定性:稳定
void Swap(int* ap, int* bp)
{
assert(ap != NULL && bp != NULL);
if (*ap > *bp)
{
int tmp = *ap;
*ap = *bp;
*bp = tmp;
}
}
void BubbleSort(int* arr, int len)
{
assert(arr != NULL);
int i = 0, j = 0;
for (i = 0; i < len; ++i)
{
for (j = 0; j < len - 1-i; ++j)
{
Swap(&arr[j], &arr[j + 1]);
}
}
}
int Print(int *arr, int len)
{
assert(arr != NULL);
BubbleSort(arr, len);
for (int i = 0; i < len; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
int main()
{
int arr[] = { 2,32,4,45,29,56,43,81,7 };
int len = sizeof(arr) / sizeof(arr[0]);
Print(arr, len);
return 0;
}
2.简单选择排序
//简单选择排序
//每一轮找到待排序序列的最小值和待排序序列的第一个值进行交换
//时间复杂度O(n^2)
//空间复杂度O(1)
//稳定性:不稳定
void SelectSort(int* arr, int len)
{
assert(arr != NULL);
int minindex;//保存最小值的下标,而不是最小值本身
for(int i = 0; i < len - 1; ++i)//控制层数
{
minindex = i;
for (int j = i + 1; j < len; ++j)//找到这一轮待排序序列的最小值的下标
{
if (arr[j] < arr[minindex])
{
minindex = j;
}
}
//第二层for循环执行结束,可以确定待排序序列中最小值的下标,保存在minindex里面
if (minindex != i)
{
int tmp = arr[minindex];
arr[minindex] = arr[i];
arr[i] = tmp;
}
}
}
int Print(int *arr, int len)
{
assert(arr != NULL);
SelectSort(arr, len);
for (int i = 0; i < len; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
int main()
{
int arr[] = { 2,1,3,9,8,7 };
int len = sizeof(arr) / sizeof(arr[0]);
Print(arr, len);
return 0;
}
3.直接插入排序
//直接插入排序
//依次从待排序序列中取值,向已排序序列中放,保证再次完全有序,直到将待排序序列中所有值取完
///时间复杂度O(n^2)
//空间复杂度O(1)
//稳定性:稳定
void InsertSort(int* arr, int len)
{
int tmp = 0;
int j;//j代表的是已排序序列中需要和tmp比较的值
for (int i = 1; i <= len - 1; ++i)
//i代表的是未排序序列中此次需要插入的值(变稳定)
{
tmp = arr[i];
for (j = i - 1; j >= 0; --j)
//j代表的是已排序序列中需要和tmp比较的值
{
if (arr[j] > tmp)
{
arr[j + 1] = arr[j];
}
else
{
break;
}
}
arr[j + 1] = tmp;
}
}
int Print(int *arr, int len)
{
assert(arr != NULL);
InsertSort(arr, len);
for (int i = 0; i < len; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
int main()
{
int arr[] = { 9,7,10,2,5,12,6,99,55,3,2,6,5,21 };
int len = sizeof(arr) / sizeof(arr[0]);
Print(arr, len);
return 0;
}
4.希尔排序
//希尔排序
//shell排序,缩小增量排序,对于直接插入排序的优化,每一次让数据变得更加稳定,直到增量为1的时候,彻底完全有序
//时间复杂度O(n^1.3~1.5)
//空间复杂度O(1)
//稳定性:不稳定
void Shell(int* arr, int len, int gap)
{
int tmp = 0;
int j;//j代表的是已排序序列中需要和tmp比较的值
for (int i = gap; i < len; ++i)
{
tmp = arr[i];
for (j = i - gap; j >= 0; j -= gap)
{
if (arr[j] > tmp)
{
arr[j + gap] = arr[j];
}
else
{
break;
}
}
//此时内层for退出,代表着tmp最终的位置已经找到
arr[j + gap] = tmp;
}
}
void ShellSort(int* arr, int len)
{
int brr[] = { 13,11,7,5,3,1 };
int len_brr = sizeof(brr) / sizeof(brr[0]);
for (int i = 0; i < len_brr; ++i)
{
Shell(arr, len, brr[i]);
}
}
int Print(int *arr, int len)
{
assert(arr != NULL);
ShellSort(arr, len);
for (int i = 0; i < len; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
int main()
{
int arr[] = { 9,7,10,2,5,12,6,99,55,3,2,6,5,21 };
int len = sizeof(arr) / sizeof(arr[0]);
Print(arr, len);
return 0;
}
5.堆排序
//堆排序,如果需要升序排序,则需要大顶堆,则将去数据调整为大顶堆,再将根节点和最后一个节点交换数据
//时间复杂度:O(nlogn)(以2为底的n)
//空间复杂度O(n)
//稳定性:不稳定
//调整一次大顶堆
void AdjustHeap(int arr[], int start, int end)
{
int tmp = arr[start];
int i = start;
int j = 2 * i + 1;
for (j; j <= end; j = 2 * i + 1)
{
if (j<end && arr[j + 1]>arr[j])
{
j++;
}
if (arr[j] > tmp)
{
arr[i] = arr[j];
i = j;
}
else
{
break;
}
}
arr[i] = tmp;
}
void HeapSort(int* arr, int len)
{
//最后一个叶子节点len-1,最后一个非叶子节点的下标为((len-1)-1)/2
//初始状态下,调整大顶堆需要,从最后一个非叶子节点开始,从后向前,从下向上调整
for (int i = (len-1-1)/2;i>=0;--i)
{
AdjustHeap(arr, i, len - 1);
//第三个参数,找不到规则,直接填最大下标位置即可(饱和时救援)
}
//此时for循环执行结束,初始状态下最繁琐的调整大顶堆搞定
for (int i = 0; i < len - 1; ++i)//轮数
{
int tmp = arr[0];//交换的是根节点arr[0],而不是arr[i]
arr[0] = arr[len - 1 - i];
arr[len - 1-i] = tmp;
AdjustHeap(arr, 0, (len-1-i)-1);
}
}
6.基数排序
```c
//基数排序(桶排序)
//时间复杂度:O(dn)
//空间复杂度:O(dn)
//稳定性:稳定
int Get_Fignure_Max(int* arr, int len)
{
int max = arr[0];
for (int i = 1; i < len; ++i)
{
if (arr[i] > max)
{
max = arr[i];
}
}
int count = 0;
while (max != 0)
{
count++;
max /= 10;
}
return count;
}
int Get_Num(int n, int index)
{
for (int i = 0; i < index; ++i)
{
n = n / 10;
}
return n % 10;
}
static void Radix(int* arr, int len,int index)
{
int brr[10][20];//申请的0-9号桶
int crr[10] = { 0 };//用crr[i]里的值代表对应的i号桶里面有多少个值
for (int i = 0; i < len; ++i)
{
int tmp = Get_Num(arr[i],index);//tmp保存着值arr[i[应该放的桶号
brr[tmp][crr[tmp]++] = arr[i];
}
int k = 0;
for (int i = 0; i <= 9; ++i)//桶号
{
for (int j = 0; j < crr[i]; ++j)
{
arr[k++] = brr[i][j];
}
}
}
void Radix_Sort(int* arr, int len)
{
int count = Get_Fignure_Max(arr, len);
for (int i = 0; i < count; ++i)
{
Radix(arr, len,i);//i=0以个位排序一次,i=1以十位排序一次,
}
}
int Print(int* arr, int len)
{
assert(arr != NULL);
Radix_Sort(arr, len);
for (int i = 0; i < len; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
int main()
{
int arr[] = { 7,5,23,4,67,45,66,99,54 };
int len = sizeof(arr) / sizeof(arr[0]);
Print(arr, len);
return 0;
}
标题7.堆排序
//堆排序,如果需要升序排序,则需要大顶堆,则将去数据调整为大顶堆,再将根节点和最后一个节点交换数据
//时间复杂度:O(nlogn)(以2为底的n)
//空间复杂度O(n)
//稳定性:不稳定
//调整一次大顶堆
void AdjustHeap(int arr[], int start, int end)
{
int tmp = arr[start];
int i = start;
int j = 2 * i + 1;
for (j; j <= end; j = 2 * i + 1)
{
if (j<end && arr[j + 1]>arr[j])
{
j++;
}
if (arr[j] > tmp)
{
arr[i] = arr[j];
i = j;
}
else
{
break;
}
}
arr[i] = tmp;
}
void HeapSort(int* arr, int len)
{
//最后一个叶子节点len-1,最后一个非叶子节点的下标为((len-1)-1)/2
//初始状态下,调整大顶堆需要,从最后一个非叶子节点开始,从后向前,从下向上调整
for (int i = (len-1-1)/2;i>=0;--i)
{
AdjustHeap(arr, i, len - 1);
//第三个参数,找不到规则,直接填最大下标位置即可(饱和时救援)
}
//此时for循环执行结束,初始状态下最繁琐的调整大顶堆搞定
for (int i = 0; i < len - 1; ++i)//轮数
{
int tmp = arr[0];//交换的是根节点arr[0],而不是arr[i]
arr[0] = arr[len - 1 - i];
arr[len - 1-i] = tmp;
AdjustHeap(arr, 0, (len-1-i)-1);
}
}
8.快速排序
//快速排序:重复划分,找基准值,将小于基准值的值全部放在左边,大于基准值的值全部放在右边:从右向左找比arr[left]更小的值,再从左向右找比arr[left]更大的值放过去,重复操作,直到left>=rigth退出
//综合情况来看,是最快的,数组越乱越有序,是每一次将基准值放到合适位置上
// 时间复杂度为O(nlogn)
// 空闲复杂度O(logn)
// 稳定性:不稳定
//
int Partition(int* arr, int left, int right)
{
int tmp = arr[left];
while (left < right)
{
while (left<right && arr[right]>tmp)
{
right--;
}
if (left == right)
{
break;
}
arr[left] = arr[right];
while (left < right && arr[left] <= tmp)
{
left++;
}
if (left == right)
{
break;
}
arr[right] = arr[left];
}
arr[left] = tmp;
return left;
}
void Quick(int arr[], int left, int right)
{
if (left < right)
{
int index = Partition(arr, left, right);
if (left < index - 1)//保证基准值左边至少有两个值
{
Quick(arr, left, index - 1);
}
if (index + 1 < right)
{
Quick(arr, index + 1, right);
}
}
}
void QuickSort(int* arr, int len)
{
Quick(arr, 0, len - 1);
}
int Print(int* arr, int len)
{
assert(arr != NULL);
QuickSort(arr, len);
for (int i = 0; i < len; ++i)
{
printf("%d ", arr[i]);
}
return 0;
}
int main()
{
int arr[] = { 9,7,10,2,5,6,12,99,55,3,2,6,5,21 };
int n = sizeof(arr) / sizeof(arr[0]);
Print(arr, n);
return 0;
}
均在vs上编译通过