```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 10
typedef struct
{
int key;
}Redtype;//一个Redtype其实就相当于一个int
typedef 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)/2
swap(&L->r[i],&L->r[i+1]);
}
}
}
//最好情况:有序:0交换,比较次数:未改进是9+8+7....+1,逆序:比较交换次数均是9+8+7+...+1
int 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 10
typedef struct
{
int key;
}Redtype;//一个Redtype其实就相当于一个int
typedef 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;//先设置为1
for(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 10
typedef 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)/2
int 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 10
typedef 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 10
typedef 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;
}