- 动态存储空间
c
语言允许在程序运行时,进行存储空间的分配,这段空间就是系统堆;- 通常申请动态内存空间使用的函数是
malloc
,函数在系统空闲内存空间中分配到合适的空间后,返回这段空间的首地址,也就是这种类型的指针值,在进行内存空间的申请时,需要指定数据空间的类型,如果函数分配空间失败,那么返回值就是NULL
;
#include<stdio.h>
#include<stdlib.h>
int main(){
int *pi=NULL;
float *pf=NULL;
//内存空间申请时,必须指定数据类型;
pi=(int *)malloc(sizeof(int));
pf=(float *)malloc(sizeof(float));
*pi=11;
*pf=12.34;
printf("The data is %d:\n",*pi);
printf("The float is %f:\n",*pf);
//在进行内存空间释放时,不需要指定类型;
free(pi);
free(pf);
}
- 在进行空间的申请时,失败的概率也是很大的,所以需要判断空间是否申请成功;
if((pi=(int*)malloc(sizeof(int)))==NULL)
sprintf(stderr,"Insufficient memory");
- 在进行内存空间的申请后,一定需要进行空间的释放,否则程序就是异常的;
- 由于系统之间的差异,在进行空间申请时,即使指定了数据类型,还是建议进行指针类型的强制转换;
pi=(int*)malloc(sizeof(int));
- 算法的一些知识:
- 定义:算法是指令的有限集合,按照顺序执行这些指令,可以完成特定的任务;
- 算法需要遵循几种原则:
- 1.输入:算法必须是可以处理一个或者几个有限个数据;
- 2.输出:算法是需要产生一定的输出的;
- 3.确定性:算法必须在确定的输入,可以得到确定的输出;
- 4.有限性:算法必须在可接受的时间内执行完成;
- 5.有效性:算法的每一步都必须是可执行的,也就是在理论和实践中是可行的;
- 先介绍关于数值交换:
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
- 在进行数值交换时,一定是需要对指针进行操作的,否则结果在本质上是不会发生改变的,数值交换也可以使用宏来实现;
#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t))
- 接下来实现一个简单排序算法:
- 选择排序
#include<stdio.h>
#include<stdlib.h>
//需要借助上面的数值交换的过程;
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void choice_sort(int array[], size_t size_of_array)
{
//选择排序关于简单的异常的处理;
if(array==NULL||size_of_array==0||size_of_array==1){
exit;
}
size_t i = 0, j = i, min = 0;
size_t k=0;
//在进行循环遍历时,i的值不可能是负数,所以不建议使用int来定义;
for (i = 0; i < size_of_array - 1; ++i)
{
min = i;
for (j = i + 1; j < size_of_array; ++j)
{
//使用内层循环的j来遍历未排序序列的数值,比较是否比当前假设的数值小,如果小,修改下标为当前下标值;
if (array[j] < array[min])
min = j;
}
//对于上述的比较结果,使用swap函数进行交换;
swap(&array[i], &array[min]);
//这里将每次交换的的结果进行简单的输出;
for(k=0;k<size_of_array;++k)
printf("%d\t",array[k]);
printf("\n");
}
}
int main()
{
int array[] = {4, 7, 9, 3, 5, 1, 6};
choice_sort(array, sizeof(array) / sizeof(int));
size_t i = 0;
for (i = 0; i < sizeof(array) / sizeof(int); ++i)
printf("%d\t", array[i]);
}
- 程序执行结果:
*选择排序动态图(借别人的一张图):
- 对于选择排序的分析:
- 1.假设按照从小到大进行排序,一开始是乱序的,首先使用一层
for
循环来进行遍历元素,并且假定当前元素是最小的; - 2.第二层
for
循环从第一层for
循环假设元素的下一个元素来进行遍历,并且和已知的假设最小元素进行比较,满足就进行交换; - 3.一直到第一层循环遍历到倒数第二个元素停止,因为最后一个元素是不用进行比较的;
- 4.选择排序算法的时间复杂度是
O(n^2)
; - 了解一下算法的稳定性:
- 1.算法的稳定性表示的是,在具有重复元素的序列里面,排序前后两个或者几个相同元素的相对顺序是否发生改变;
- 假设序列
1,5a,8,0,4,7,5b,9,0
,假设5a
和5b
表示的都是5
这个元素,排序之后的结果如果是0,0,1,4,5a,5b,7,8,9
,这个算法就是稳定的,当然这这里的意思是所有的重复元素的相对顺序都不发生改变,只要有一组员素发生改变,都不属于稳定的排序算法,相反不稳定的排序算法的结果就是0,0,1,4,5b,5a,7,8,9
; - 首先选择排序属于不稳定的排序算法,应该这样进行分析:
*假设已知序列为1,5a,8,0a,9,7,5b,4,0b
手写一下排序的过程应该是这样的:
*按照上面的排序过程5a
和5b
的相对位置已经发生改变,所以可以证明选择排序是不稳定的算法;
选择排序的C++
实现:
- 1.假设按照从小到大进行排序,一开始是乱序的,首先使用一层
#include<iostream>
using namespace std;
//T 这里使用了模板编程的函数编程的一点知识,T的类型可以跟据已经传递参数的类型自动进行推导可以处理int,float,double等常见类型,代码的复用性要比单纯定义int一种类型的更好,这也是模板编程的优势;
template<class T>
//这里不在使用指针,使用C++语言的引用来进行处理,对应于引用是必须绑定一个相同类型的对象的,引用不应该为空;
void myswap(T &left, T &right)
{
//添加一些异常处理的判断
if(left==right)
exit;
T temp;
temp = left;
left = right;
right = temp;
}
template<class T>
void Choice_sort(T array[], size_t sizeof_array)
{
T min;
for(size_t i=0;i<sizeof_array-1;++i){
min=i;
for(size_t j=i+1;j<sizeof_array;++j){
if(array[j]<array[min])
min=j;
}
myswap(array[i],array[min]);
}
}
int main()
{
int array[]={5,5,3,2,1,6,7,4,3,9,1,3,0};
Choice_sort(array,sizeof(array)/sizeof(int));
for(auto X:array)
cout << X << " ";
cout << endl;
}
- 建议使用
C++
的代码进行验证; - 上面描述的遍历都是从前往后进行遍历的,其实从后往前也是可以进行遍历的,实现也不是很难,建议可以试一下;