最近老师在讲算法分析和设计,数据结构忘了许多,所以借此复习一下。
准备工作:
软件microsoft visual studio
在头文件,我定义了一个结构体,包含数组和长度
#include<stdio.h>
#include<malloc.h>
typedef struct array
{
int num[20];
int length = 0;
};
void shows(array* p);
void insertion_sorting(array* p);
void bubble_sorting(array* p);
void quick_sorting(array* p, int A, int B);
void merge_sort(array* p);
输出函数shows()
//输出函数
void shows(array *p)
{
for (int i = 0; i < p->length; i++) {
printf("%d \t", p->num[i]); //*p解地址,p还可以当做数组名使用
}
printf("\n");
}
main文件,创建实例
//测试用例的创建和展示
array *example;
example = (array*)malloc(sizeof(array));
if (example == NULL) {
printf("error");
return 0;
}
int a[] = { 5,9,1,6,11,7,8,13,4 };
example->length = sizeof(a) / sizeof(a[0]);
//此处sizeof得出的结果是一个unsigned long long 型的数据,所以不能直接进行赋值,需要强制转为int
for (int i = 0; i < example->length; i++) {
example->num[i] = a[i];
}
1.插入排序
思想:从第二个数开始,先用一个哨兵把该数存起来,然后依次与前面的数比较。如果该数比较小,则前一个数向后移一位,出现一个空位,继续往前比较。直到前面的数比较完,或者出现比该数小的数,此轮比较结束,将该数插入空位。
代码如下
//插入排序
void insertion_sorting(array* p) {
int a;
for (int i = 1; i < p->length; i++) {
a = p->num[i];
for (int j = i-1; j >= 0; ) {
if (a < p->num[j]) {
p->num[j+1] = p->num[j];
j--;
//a用来暂存num[i],当a应该放在第一位时,则
if (j < 0) {
p->num[j+1] = a;
break;
}
}
else { //如果a应该放在非第一位,则
p->num[j+1] = a;
break;
}
}
}
}
2.冒泡排序
思想:每次循环,取第一个数与第二个数比较,将大的数换到后面,然后是第二个数与第三个数比较,依次类推。
代码如下
//冒泡排序
void bubble_sorting(array* p)
{
int a;
for (int i = 1; i < p->length; i++) { //第一层的i是循环次数(因为剩下最后一个数时不用比较,
//所以length-1次即可),第二层的j是下标,需要和所有未排序的数进行比较,length-i次即可。
for (int j = 0; j < p->length - i; j++) {
if (p->num[j] > p->num[j + 1]) {
a = p->num[j + 1];
p->num[j + 1] = p->num[j];
p->num[j] = a;
}
}
}
}
3.快速排序
思想:取第一个数为标准量criterion,从左右两边出发,如果左边遇到比criterion大的就暂停,右边如果遇到比criterion小的也暂停,如果两边尚未相遇,则交换两边的数。最后将标准量换到分界位置,将数组分为左右两个部分,左边都是比criterion小,右边都比criterion大,然后对左右两边分别继续进行上述步骤。(递归)
代码如下
//快速排序
void quick_sorting(array* p,int A, int B) //AB为数组左右两边端点的下标
{
if (A >= B) return;
int criterion = p->num[A];
int a, b;
int temp;
a = A, b = B+1;
while (a < b)
{
do a++; while (p->num[a] < criterion); //从左向右移动,找出所有大于标准(creterion)的
do b--; while (p->num[b] > criterion);//从右向左移动,找出所有小于标准(creterion)的
if (a < b) { // 交换位置,使得以creterion为分界线,左边全部小于他,右边全部大于他。
temp = p->num[b];
p->num[b] = p->num[a];
p->num[a] = temp;
}
}
p->num[A] = p->num[b]; //如果ab最后下表相同则这里用ab都可以,如果是b<a,则应该使用下标b
p->num[b] = criterion;
quick_sorting(p, A, b-1); // 递归,标准量不计入递归
quick_sorting(p, b + 1, B);
}
4归并排序
思想:将数组从中间分开,然后对分开的两部分再分,重复上述操作,直到不可再分。然后将分开部分两两比较,重新归并到一起。(递归)
代码如下
//归并排序
void merge_sorting(array *p,int A,int B, int *tmp)
{
if (A >= B) return;
int mid = (A + B+1) / 2;
merge_sorting(p, A, mid-1 ,tmp);
merge_sorting(p, mid, B,tmp);
int beg1 = A, end1 = mid - 1, beg2 = mid, end2 = B;
int index = A;
while (beg1 <= end1 && beg2 <= end2) {
if (p->num[beg1] < p->num[beg2]) {
tmp[index] = p->num[beg1]; //这三行可以写成一行,如下
index++;
beg1++;
}
else {
tmp[index++] = p->num[beg2++];
}
}
while (beg1 <= end1)
{
tmp[index++] = p->num[beg1++];
}
while (beg2 <= end2)
{
tmp[index++] = p->num[beg2++];
}
//将归并完的数拷贝回原数组
for (int i = A; i <= B; i++)
{
p->num[i] = tmp[i];
}
}
/*
递归的原理
每级函数调用都有自己的变量
每次函数调用都会返回一次
递归函数中位于递归调用之前的语句,按照被调函数的顺序执行
递归函数中位于递归调用之后的语句,按照被调函数相反的顺序执行
(嵌套在最里面的那一层的语句先执行,因为最里面那一层最先返回)
递归函数必须包含能让递归停止调用的语句(return)。
因此每次递归调用的形参都要使用不同的值。
*/
void merge_sort(array* p) {
int* tmp;
tmp = (int*)malloc(sizeof(p->num));
merge_sorting(p, 0, p->length - 1, tmp);
free(tmp);
}