排序分类:插入排序,选择排序,交换排序,归并排序(不讨论)
插入排序:直接插入排序,希尔排序
选择排序:简单选择排序,堆排序
交换类排序:冒泡排序,快速排序
typedef struct {
int *date;
int lenth;
}sqlist;
一.冒泡排序算法
/**************冒泡排序算法实现************/
// 时间复杂度=O(n*n)
//思想:从后往前,不断比较相邻连个数的大小,将小的数放在前面
int SelectSort(sqlist *L)
{
int i = 0;
int j = 0;
int flag = 1;
for (i = 0; i < L->lenth&&flag; i++)
{
flag = 0; //初次遍历数组时初始化为0,如果遍历完后没有数据交换
// 说明此时后面的数据是有序排列
for (j = L->lenth - 2; j >= i; j--) //从后往前进行比较犟嘴晓得一个数放在第i个位置
{
if (L->date[j]>L->date[j+1]) //若前者大于后者交换两者数据
{
L->date[j] = L->date[j] ^ L->date[j+1];
L->date[j+1] = L->date[j] ^ L->date[j + 1];
L->date[j] = L->date[j] ^ L->date[j + 1];
flag = 1;//遇到数据交换置1
}
}
}
return 0;
}
二.简单选择排序算法
/**************简单选择排序算法实现************/
// 时间复杂度=O(n*n)
//与冒泡排序相似只不过简单选择排序是再一次循环中找到最小值下标,在循环结束后才进行值得交换
//虽然时间复杂度相同,但是简单选择排序的性能优于冒泡排序
int SelectSort(sqlist *L)
{
int i = 0;
int j = 0;
int min = 0;
for (i = 0; i < L->lenth; i++)
{
min = i; //记录当前下标
for (j = L->lenth - 1; j > i; j--) //从后往前进行比较犟嘴晓得一个数放在第i个位置
{
if (L->date[min]>L->date[j ]) //若前者大于后者交换两者数据
{
min = j; //如果下标j的置小于min下标表示的值,记录最小下标
}
}
if (min != i)
{
L->date[min] = L->date[min] ^ L->date[i];
L->date[i] = L->date[min] ^ L->date[i];
L->date[min] = L->date[min] ^ L->date[i];
}
}
return 0;
}
三.直接插入排序算法
/********直接插入排序*******/
//时间复杂度:O=(n*n)算法性能优于冒泡和简单选择
//思想:
//分段比较:即是从数组中第二个元素开始一次和前面的一个比较。
//若果购后面一个小于前面一个,那么记录这个数字,将前面的数据后移直到前出现一个数
//小于这个记录的数,停止移动,降记录的数据插入即可。
int InsertSort(sqlist *L)
{
int i,j;
int flag = 0;
i = j = 0;
for (i = 1; i < L->lenth; i++) //从第二个数开始判断前一个和后一个大小关系
{
if (L->date[i] < L->date[i - 1]) //判断前后数据的大小关系
{
flag = L->date[i]; //记录这个小的数
for (j = i - 1; flag<L->date[j]&&j>-1; j--) //数据后移直到出现一个数小于flag为止
//或者遍历完整个子数组序列为止(此时j=-1)
{
L->date[j + 1] = L->date[j];
}
L->date[j + 1] = flag; //插入到合适位置
}
}
return 0;
}
四.希尔排序算法
/********希尔排序*******/
//时间复杂度:O=(n的2/3次方)要好于直接排序
//注意:增量序列(increment)的最后一个增量值必须等于1,即是必须要做一次直接插入排序
//希尔排序并不是一种稳定的排序算法
//增量(increment)选取参考大话数据结构P395的介绍
//思想:
//1:选取合适分段区间
//2:以这个分段区间为间隔执行插入排序
//例如:{ 50, 10, 60, 70, 20, 40, 80, 1, 15 }若是分段区间为2则;
//对{50,60,20,80,15}这个子序列执行直接插入排序
int ShellSort(sqlist *L)
{
int i, j;
int increment = L->lenth;
int flag = 0;
i = j = 0;
while (increment > 1)
{
increment = increment / 3 + 1; //注意值了不要把3换为2不然会出现increment=2时 increment / 3 + 1恒为2死循环
for (i = increment ; i <L->lenth; i++)
{
if (L->date[i] < L->date[i - increment])
{
flag = L->date[i];
for (j = i - increment; (j>-1) && (flag < L->date[j]); j = j - increment)
{
L->date[j + increment] = L->date[j];
}
L->date[j+increment] = flag;
}
}
}
return 0;
}
五.堆排序算法
///********堆排序*******/
//时间复杂度:O=(nlogn) (排序优选项)
//思想:不断构造大顶堆,然后将最大值(根的值)放入数组末尾
//继续从lenth-2(末尾前一个)继续构造大顶堆依次下去
//注意大顶堆特点:所有根节点的值逗比左右子节点值大
//堆排序时间复杂度:O=(nlogn)空间复杂度O=1,而由于构建堆所需
//的次数比较多,因此它并不适合待排个数较少情况
//以根节点为中心遍历树,将根节点下面的子树(包括根)按照根的数值最大排序
int HeapAdjust(sqlist *L, int s, int max)
{
int temp, j;
temp = L->date[s]; //记录根的值
for (j = 2 * s; j <=max; j = j * 2) //从s根节点的左子树开始遍历
{
if (j < max&&L->date[j] < L->date[j + 1]) //左子树小于右子树
j++;
if (temp >= L->date[j]) //根大于该数的最大节点那么退出
break;
L->date[s] = L->date[j]; //交换根的值
s = j; //以这个节点为根继续向下排序,使得根为最大的数
}
L->date[s] = temp;
return 0;
}
void HeapSort(sqlist *L) //堆排序算法
{
int i;
for (i = L->lenth / 2; i > -1; i--)//构建大顶推使得每科字数的根节点为最大节点
HeapAdjust(L, i, L->lenth);
for (i = L->lenth-1; i > 0; i--) //交换数据
{
L->date[0] = L->date[0] ^ L->date[i];
L->date[i] = L->date[0] ^ L->date[i];
L->date[0] = L->date[0] ^ L->date[i];
HeapAdjust(L, 0,i-1); //以根节点(第一个节点)目标找到最大值放在根节点位置
}
}
六.快速排序算法
/******快排算法实现*/
//时间复杂度:最优:O=(nlogn),平均:(n*n)
//思想;选取一个关键字使得比这个关键字小的数位于他的左边,比他大的位于右边
//重复进行,不断将整个序列划分为若干个子序列
//low:待交换的数组起始位置
//high:待交换的数组末尾起始位置
int partiton(sqlist *L, int low, int high) //使得关键左边的数小于关键字右边的数大于关键字
{
int pivotkey; //定义关键字变量
pivotkey = L->date[low];//关键字取线性表中的第一个元素
while (low < high)
{
while (low < high&&L->date[high] >= pivotkey)//low < high限制low和high最终指向同一个元素也就是pinokey的值
high--; //如果没有这条限制语句那么最终low和high不会指向同一个数(low<high或者high),
//那么我们在后面就要判断pinokey的坐标值是位于low还是high
if (L->date[low] != L->date[high])
{
L->date[low] = L->date[low] ^ L->date[high];
L->date[high] = L->date[low] ^ L->date[high];
L->date[low] = L->date[low] ^ L->date[high];
}
while (low < high&&L->date[low] <= pivotkey)
low++;
if (L->date[low] != L->date[high]) //避免两者相等时出现交换失败
{
L->date[low] = L->date[low] ^ L->date[high];
L->date[high] = L->date[low] ^ L->date[high];
L->date[low] = L->date[low] ^ L->date[high];
}
}
return low;
}
int qsort(sqlist *L, int low, int high) //划分序列
{
int pivot;
if (low < high)
{
pivot = partiton(L, low, high);
qsort(L,low,pivot-1); //递归排序左边
qsort(L, pivot +1,high); //递归排序右边
}
return 0;
}
所有的算法都测试通过,如果出现问题可联系笔者,或者换个姿势。。。。
注意:由于使用异或运算交换两个元数的值得时候如果两个元数相等那么会出现交换失败导致两个数的值都为0
例如:
int a,b;
a=b=5;
a=a^b;
b=a^b;
a=a^b;
结果b=a=0
经过测试除了直接插入排序要加条件判断外其他几种排序算法都可以不用加上条件判断。