起泡(冒泡)法排序
基本思路:每次将相邻两个数比较,将小的(大的)调到前边。
如果有n个数,则要进行n-1趟比较,在第一趟中进行n-1次两两比较,在第j趟中进行n-j次两两比较。
时间复杂度:O(n^2) 最坏N^2最好N
本代码从小到大排序
#include <stdio.h>
int main()
{
int i,j,t,a[11]; //定义变量及数组为基本整型
printf("请输入10个数:\n");
for(i=1;i<11;i++)
scanf("%d",&a[i]); //从键盘中输入10个数
for(i=1;i<10;i++) //变量i代表比较的趟数
for(j=1;j<10-i;j++) //变最j代表每趟两两比较的次数
if(a[j]>a[j+1])
{
t=a[j]; //利用中间变量实现两值互换
a[j]=a[j+1];
a[j+1]=t;
}
printf("排序后的顺序是:\n");
for(i=1;i<=10;i++)
printf("%5d",a[i]); //将冒泡排序后的顺序输出
printf("\n");
return 0;
}
快排
思路:
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的左序列和右序列再次进行这种单趟排序,如此反复操作下去,直到左右序列只有一个数据,或是左右序列不存在时,便停止操作,此时此部分已有序
时间复杂度:N*logN
#include <stdio.h>
int qusort(int s[],int start,int end) //自定义函数 qusort()快速排序
{
int i,j;
i=start; //将每组首个元素赋给i
j = end; //将每组末尾元素赋给j
s[0]=s[start]; //设置基准值
while(i<j)
{
while(i<j&&s[0]<s[j])
j--; //位置左移
if(i<j)
{
s[i]=s[j]; //将s[j]放到s[i]的位置上
i++; //位置右移
}
while(i<j&&s[i]<=s[0])
i++; //位置左移
if(i<j)
{
s[j]=s[i]; //将大于基准值的s[j]放到s[i]位置
j--; //位置左移
}
}
s[i]=s[0]; //将基准值放入指定位置
if (start<i)
qusort(s,start,j-1); //对分割出的部分递归调用qusort()函数
if (i<end)
qusort(s,j+1,end);
return 0;
}
int main()
{
int a[11], i; //定义数组及变量为基本整型
printf("请输入10个数:\n");
for(i=1;i<=10;i++)
scanf("%d",&a[i]); //从键盘中输入10个要进行排序的数
qusort(a,1,10); //调用qusort()函数进行排序
printf("排序后的顺序是:\n");
for(i=1;i<=10;i++)
printf("%5d",a[i]); //输出排好序的数组
printf("\n");
return 0;
}
插入排序
插入排序是把一个记录插入到已排序的有序序列中,使整个序列在插入该记录后仍然有序。插入排序中较简单的种方法是直接插入排序,其插入位置的确定方法是将待插入的记录与有序区中的各记录自右向左依次比较其关键字值的大小。本实例要求使用直接插入排序法将数字由小到大进行排序。
时间复杂度:最坏情况下为O(N*N),此时待排序列为逆序,或者说接近逆序
最好情况下为O(N),此时待排序列为升序,或者说接近升序。
空间复杂度:O(1)
#include <stdio.h>
int insort(int s[], int n) /* 自定义函数 insort()*/
{
int i,j;
for(i=2;i<=n;i++) //数组下标从2开始,s[0]做监视哨,s[1]一个数据无可比性
{
s[0]=s[i]; //给监视哨陚值
j=i-1; //确定要比较元素的最右边位置
while(s[0]<s[j])
{
s[j+1]=s[j]; //数据右移
j--; //移向左边一个未比较的数
}
s[j+1]=s[0]; //在确定的位置插入s[i]
}
return 0;
}
int main()
{
int a[11],i; //定义数组及变量为基木整型
printf("请输入10个数据:\n");
for (i =1;i<=10;i++)
scanf("%d",&a[i]); //接收从键盘输入的10个数据到数组a中
printf("原始顺序:\n");
for(i=1;i<11;i++)
printf("%5d",a[i]); //将未排序前的顺序输出
insort(a,10); //调用自定义函数 insort()
printf("\n 插入数据排序后顺序:\n");
for(i=1;i<11;i++)
printf("%5d",a[i]); //将排序后的数组输出
printf("\n");
return 0;
}
选择排序
思路:每次从待排序列中选出一个最小值,然后放在序列的起始位置,直到全部待排数据排完即可。
实际上,我们可以一趟选出两个值,一个最大值一个最小值,然后将其放在序列开头和末尾,这样可以使选择排序的效率快一倍。
程序中用到两个 for 循环语句。第一个 for 循环是确定位置的,该位置是存放每次从待排序数列中经选择和交换后所选出的最小数。第二个 for 循环是实现将确定位置上的数与后面待排序区间中的数进行比较的。
时间复杂度:最坏情况:O(N^2)
最好情况:O(N^2)
空间复杂度:O(1)
#include <stdio.h>
int main()
{
int i,j,t,a[11];
printf("请输入10个数:\n");
for(i=1;i<11;i++)
scanf("%d",&a[i]); //从键盘中输入要排序的10个数字
for(i=1;i<=9;i++)
for (j=i+1;j<=10;j++)
if(a[i]>a[j]) //如果前一个数比后一个数大,则利用中间变量t实现两值互换
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
printf("排序后的顺序是:\n");
for(i=1;i<=10;i++)
printf("%5d", a[i]); //输出排序后的数组
printf("\n");
return 0;
}
二分插入
void half_insert_sort(int arr[],int len)
{
int i,j;
for(i=1;i<len;i++)
{
int key = arr[i];
int left = 0;
int right = i-1;
while(left<=right)
{ //半分查找找到插入的位置
int mid = (left+right)/2;
if(key<arr[mid])
{
right = mid-1;
}
else
{
left = mid+1;
}
}
for(j=i-1;j>=left;j--)
{ //把后面的元素往后移
arr[j+1]=arr[j];
}
arr[j+1] = key; //插入元素
}
}
堆排序
思路:把数据进行大堆化,然后依次交换堆顶(最大值)和最后一个元素,在使堆顶重新大堆化,最后循环过后数组便有序。
过程:
最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
创建最大堆(Build Max Heap):将堆中的所有数据重新排序
堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算
时间复杂度:O(nlgn) 稳定性:不稳定的算法
堆排序(降序)的核心思想:因为建小堆可以选出最小的数即根节点,我们将每次建好的小堆的最后一个叶子节点和根节点进行交换,交换后不把最后一个数看作堆里的数据,此时根的左右子树依旧是大堆,然后我们再用向下调整算法选出次小的如此循环直到堆里剩一个数结束
• 升序建大堆
• 降序建小堆
代码:
void re_heap(int arr[],size_t index,size_t len){
size_t child = 2*index+1; //左节点坐标
int key = arr[index]; //当前节点值
while(child<len){
if(child+1<len&&arr[child]<arr[child+1]){ //如果右节点存在且右节点的值比左节点大,那就child记录较大字节点的坐标
child++;
}
if(arr[child]>key){ //如果子节点的值比根节点的值大
arr[index] = arr[child]; //改变根节点的值
}else{
break;
}
index = child;
child = 2*index+1;
}
arr[index] = key; //插入记录好的值
}
void heap_sort(int arr[],size_t len){
int i;
for(i=len/2;i>=0;i--){
re_heap(arr,i,len); //对第i个根节点进行大堆化
}
for(i=len-1;i>0;i--){
swap(&arr[0],&arr[i]); //交换第一个和最后一个元素
re_heap(arr,0,i); //对第一个元素进行大堆化
}
}