
```c
//非规范的冒泡排序,从头开始,一般是相邻比较,大的往后,一轮下来到靠后位置
include”stdio.h”
define MAXSIZE 10
void swap(int a,int b)
{
int t;
t=a;
a=b;
b=t;
}
void Bubblesort(int *a)
{ for(int j=0;j<9;j++)
{
for(int i=1;i
```c//规范的冒泡排序,从头开始,一般是相邻比较,小的往上冒,一趟下来有一个小的产生#include"stdio.h"#define MAXSIZE 10typedef struct{int key;}Redtype;//一个Redtype其实就相当于一个inttypedef struct{Redtype * r;//r[0]空出来int length;}Sqlist;void swap(int *a,int *b){int t;t=*a;*a=*b;*b=t;}void Bubblesort(Sqlist *L){ for(int j=0;j<9;j++){for(int i=L->length-1;i>=1;i--)//从末尾开始{if(L->r[i+1]<L->r[i]) //后一个比前一个小,则交换//10数据比较9次,9个数据比较8次....9+8+7+...+1=n(n-1)/2swap(&L->r[i],&L->r[i+1]);}}}//最好情况:有序:0交换,比较次数:未改进是9+8+7....+1,逆序:比较交换次数均是9+8+7+...+1int main(){int a[MAXSIZE+1]={0,1,4,5,6,7,8,9,10,2,3};Sqlist L;L.length=10;L.r=a;Bubblesort(&L);for(int i=1;i<=L.length;i++){printf("%d ",L.r[i]);}}
//最终版的冒泡排序#include<stdio.h>#define MAXSIZE 10typedef struct{int key;}Redtype;//一个Redtype其实就相当于一个inttypedef struct{Redtype * r;//r[0]空出来int length;}Sqlist;void swap(Redtype *a,Redtype *b){Redtype t;t=*a;*a=*b;*b=t;}void Bubblesort(Sqlist *L){int flag=1;//先设置为1for(int j=0;j<L->length-1&&flag;j++){flag=0;//没有交换,flag的值为0,提前终止for(int i=L->length-1;i>=1+j;i--)//从末尾开始,i>1+j理解上是为了减少没必要的排序{if(L->r[i+1].key<L->r[i].key) //后一个比前一个小,则交换{swap(&L->r[i],&L->r[i+1]);flag=1;//发生交换}}}}//改进后:最好正序,比较n-1次->O(n),交换0次,最坏9+8+7+...1->比较=交换=n-1+...1,时间复杂度为O(n^2)int main(){int a[MAXSIZE+1]={0,1,4,5,6,7,8,9,10,2,3};Sqlist L;L.length=10;L.r=(Redtype*)a;//左右类型一样Bubblesort(&L);for(int i=1;i<=L.length;i++){printf("%d ",L.r[i]);}}//简单选择排序:每一次在n-i+1个,ri....rn个中找到合适的与之交换#include "stdio.h"#define MAXSIZE 10typedef struct{int key;}Redtype;typedef struct{Redtype * r;int length ;}Sqlist;void swap(Redtype *a,Redtype *b);//交换操作void Simplesort(Sqlist *L);//简单选择排序void SortPrint(Sqlist *L);int main(){Sqlist L;int a[MAXSIZE+1]={0,1,3,5,7,9,2,4,6,8,10};L.length=MAXSIZE;L.r=(Redtype*)a;Simplesort(&L);SortPrint(&L);}void swap(Redtype *a,Redtype *b){Redtype t;t=*a;*a=*b;*b=t;}void Simplesort(Sqlist *L){ int j;for(j=1;j<=L->length-1;j++)//n个数据,交换n-1次{ //寻找合适的位置,从n-i+1中寻找int min=j;//设置下标 1:2-10,2:3-7...9:10 9+8+7+6...+1 n*(n-1)/2int k;for(int i=j+1;i<=L->length;i++){if(L->r[i].key<=L->r[min].key){min=i;//记录找到的位置,更新最小值}}swap(&L->r[min],&L->r[j]);}}/**n-i+1,最好和最坏:第i趟,n-i比较,总和n*(n-1)/2次*交换次数最好0次,最坏同比较*总复杂度O(n*2)*/void SortPrint(Sqlist *L){for(int i=1;i<=L->length;i++){printf("%d ",L->r[i].key);}}//时间复杂度同冒泡排序,但是略优于冒泡排序//直接插入排序算法:哨兵 is important 作为辅助空间和判断依据#include"stdio.h"#define MAXSIZE 10typedef struct{int key;}Redtype;typedef struct{Redtype * r;int length;}Sqlist;void StrInsertsort(Sqlist * L);void LinkPrint(Sqlist *L);int main(){int a[MAXSIZE+1]={0,2,4,6,8,10,1,3,5,7,9};Sqlist L;L.r=(Redtype *)a;L.length=MAXSIZE;StrInsertsort(&L);LinkPrint(&L);return 0;}/**第一个元素默认在有序表中,所以考虑r2...rn这些位置* 哨兵的作用为作为辅助空间和防止越界代替i>=0类似的写法;* 注意的地方是两个for的写法*/void StrInsertsort(Sqlist *L){ int j;for(int i=2;i<=L->length;i++) //{L->r[0].key=L->r[i].key;if(L->r[i].key<L->r[i-1].key){for( j=i-1;L->r[0].key<L->r[j].key;j--) //重要点。L->r[j+1]=L->r[j];L->r[j+1]=L->r[0];}}}/***时间复杂度分析:*最好:正序:n-1外循环,内循环比较1次,最终为n-1个1相加,移动0次*最坏:逆序:n-1趟,第k趟,移动k+2(哨兵的移动)次 3+4+5+...+n+1=(n+4)*(n-1)/2* 比较次数 ,第k趟,比较k+1(for2)次,2+3+...+n=(n+2)*(n-1)/2* 细节理解说明:for2:for( j=i-1;L->r[0].key<L->r[j].key;j--)* i-1;比较i次0与0也算一次* 综合考虑:根据概率相同原则:平均比较和移动次数均是n^2/4* O(n^2)* 同样的时间复杂度:直接插入排序比冒泡排序和简单选择排序更好一些* (一) 基本有序时,1+1+1+...kn(很少项较大),移动kn,整体较小* (二)n较小,L->length较小,对n^2的影响较大,此时优势明显*/void LinkPrint(Sqlist *L){for(int i=1;i<=L->length;i++)printf("%d ",L->r[i].key);}/**Shellsort :希尔排序,优化后的直接插入排序,历史意义在于时间复杂度的突破*直接插入排序的优势在于在数据基本有序,数量较少时这两个条件下,优势明显*而希尔排序应创造这样的优势性条件,使数据变少和基本有序*变少的有效措施是分割数据,及分组,在组内内部直接插入排序,如何分割*在基本有序时在进行一次直接插入排序,基本有序,小的基本在前面,大的在后面,不大不小在中间*算法核心:采用跳跃分割策略,保证基本有序而非局部有序**/#include"stdio.h"#define MAXSIZE 10typedef struct{int key;}Redtype;typedef struct{Redtype *r;int length;}Sqlist;void Shellsort(Sqlist *L);void StrInsertsort(Sqlist *L,int gap);void SortPrint(Sqlist *L);void swap(Redtype *a,Redtype *b);int main(){Sqlist L;int b=MAXSIZE;int a[MAXSIZE+1]={0,9,8,7,6,5,1,2,3,4,10};L.r=(Redtype*)a;L.length=MAXSIZE;Shellsort(&L);SortPrint(&L);return 0;}void Shellsort(Sqlist *L){ int b=L->length/2;while(b){StrInsertsort(L,b);b/=2;}}void StrInsertsort(Sqlist *L,int gap){ int i;//printf("%d %d ",L->r[6].key,L->r[8].key);for(i=1;i+gap<=L->length;i++){ if(L->r[i].key>L->r[i+gap].key)//交换的条件***swap(&(L->r[i]),&(L->r[i+gap]));}}//9,8,7,6,5,1,2,3,4,10/* gap=5*结尾=5:1,8,7,6,5,9,2,3,4,10* =6:1,2,7,6,5,9,8,3,4,10* =7:1,2,3,6,5,9,8,7,4,10* =8:1,2,3,4,5,9,8,7,6,10* =9:1,2,3,4,5,9,8,7,6,10* =10:1,2,3,4,5,9,8,7,6,10** gap=2* 1,2,3,4,5,9,8,7,6,10* 1,2,3,4,5,7,8,9,6,10* 1,2,3,4,5,7,6,9,8,10** gap=1* 1,2,3,4,5,6,7,9,8,10* 1,2,3,4,5,6,7,8,9,10*/void swap(Redtype *a,Redtype *b){Redtype t;t=*a;*a=*b;*b=t;}void SortPrint(Sqlist *L){for(int i=1;i<=L->length;i++)printf("%d ",L->r[i].key);printf("\n");}
/*堆排序:历史溯源:发明堆排序的人同样发明了对这样的数据结构:heap chunk
* 了解大根堆和小根堆的概念
* 简单选择排序:在n个元素中选择最小的需要比较n-1次,其中造成很多无效的比较
* 而堆排序可以记录下来,规避简单选择排序的缺点,改进后的选择排序
* 利用大根堆的
* 问题数目不是完全二叉树的如何更变为大根堆,必须奇数个
*/
#include"stdio.h"
#define MAXSIZE 9
typedef struct
{
int key;
}Redtype;
typedef struct
{
Redtype *r;
int length;
}Sqlist;
void HeapAdjust(Sqlist *L,int s,int m); //s是其实下标,m是末尾下标
void Heapsort(Sqlist *L);
void SortPrint(Sqlist *L);
void swap(Redtype *a,Redtype *b);//交换记录
int main()
{ int a[MAXSIZE+1]={0,5,1,9,3,7,4,8,6,2};
Sqlist L;
L.r=(Redtype*)a;
L.length=MAXSIZE;
Heapsort(&L);
SortPrint(&L);
return 0;
}
void SortPrint(Sqlist *L)
{
for(int i=1;i<=L->length;i++)
printf("%d ",L->r[i].key);
}
//核心的思想,子树的根节点及孩子的大小的比较
void HeapAdjust(Sqlist *L,int s,int m)
{
int j;//temp的用途在于完成根与孩子的交换,存储元素,j的话与之相关的是2*j,2*j+1,左右孩子
Redtype temp;
temp=L->r[s];//由于在堆的实际排序中根节点很有用,记录根节点
for(j=2*s;j<=m;j++)//孩子不超过n的范围
{
if(j<m&&L->r[j].key<L->r[j+1].key)
j++;//j记录的是孩子中较大的那一方的下标
if(temp.key>=L->r[j].key)//跟两个孩子中较大的比较之后,如果是大根堆,则打断循环
break;
//否则的话就赋值(此时有两个一样的数)
L->r[s]=L->r[j];//j的角标那一项比较大
s=j;
}
L->r[s]=temp;//如果进行了赋值,那就要想办法改变赋值的影响:即将temp赋值给新的s的位置
//完成交换,这算法有些复杂
}
void Heapsort(Sqlist *L)
{
int i;
for(i=L->length/2;i>0;i--)//将一个无序列调整为大根堆,从n/2开始,比起小的均为分支节点
HeapAdjust(L,i,L->length); //n
//SortPrint(L);
for(i=L->length;i>1;i--)
{
swap(&L->r[1],&L->r[i]);//堆顶与最后一个交换
HeapAdjust(L,1,i-1);//生成数目减一的大根堆,从根节点开始调整
}
}
//时间复杂度分析:主要操作为初始化堆和重建堆
/*
* 先来看初始化堆:堆的初始化主要是从最下层的分支节点与左右孩子比较,有必要时交换
* 初始堆:最不利的情况是n/2*2=n次交换,时间复杂度O(n)
* 在HeapAdjust中重建中时由于循环体j=2*j<=m,结合完全二叉树的性质即:从某一节点到根节点的距离log2i(向下取整)+1
* j=2*j实际上和log2i+1循环次数相近,而Heapsort进行n-1的堆重建(伴随去n-1的堆顶记录),综合在重建堆时的时间复杂度为O(n*logn)
*/
void swap(Redtype *a,Redtype *b)
{
Redtype t;
t=*a;
*a=*b;
*b=t;
}
