这几天把学到的几种排序整理了一下。除了之前发过的冒泡和选择,别的我都发出来了。
首先是插入排序
/*
2017年8月3日19:12:27
目的 : 插入排序 (升序)
*/
#include<stdio.h>
void insertsort(int *a, int len)
{
int i,j; //i表示第几个元素插入到前已经排序好的数组中
//j表示从i前面一个开始找i应该被插入的位置
int tmp ;
for(i=1;i<len;i++) //下标从一开始,第一个默认排序
{
j = i-1;
tmp = a[i];
while(j>=0 && a[j]>tmp)
{
a[j+1] = a[j]; //把比tmp大的都往后面移一个
j--;
}
a[j+1] = tmp; //当循环结束,j是指向第一个比他小的元素,若没有,则就是这个数组的一个的前面一个。
}
}
void printA(int *a,int len)
{
int i;
for(i=0;i<len;i++)
printf("%4d",a[i]);
printf("\n");
}
int main()
{
int a[10] = {9,8,7,6,5,4,3,2,1,0};
int len = sizeof(a)/sizeof(a[0]);
insertsort(a,len);
printA(a,len);
return 0;
}
然后是希尔排序
/*
2017年8月3日19:12:27
目的 : 希尔排序(升序)
思路 : 插入排序是每一个一个找,插入,希尔是每d个,把一个数组竟可能排序号,最后调用一次插入排序
*/
#include<stdio.h>
void printA(int *a,int len)
{
int i;
for(i=0;i<len;i++)
printf("%4d",a[i]);
printf("\n");
}
void shellsort(int *a ,int len )
{
int i,j;
int d = 0;
while(d<len)
{
d = d*3 +1; //保存初始间隔 0 1 4 13 ..
}
while(d>0)
{
//内部就是插入排序,间隔为d
for(i=1;i<len;i++)
{
int tmp = a[i];
j = i-d;
while(j>=0 && a[j]>tmp) //大于就往前走
{
a[j+d] = a[j];
j = j-d;
}
a[j+d] = tmp;
}
d = (d-1)/3;
}
}
int main()
{
int a[10] = {9,8,7,6,5,4,3,2,1,0};
int len = sizeof(a)/sizeof(a[0]);
shellsort(a,len);
printA(a,len);
return 0;
}
堆排序
/*
2017年8月3日20:13:47
目的 : 堆排序 (升序)
思路 : 要实现一个二叉树堆,最关键是利用二叉树的一些性质,
这里的推排序,并不是真正去创建一个二叉树堆,而是通关二叉树堆的性质去模拟堆。
数组,内存,都是线性的,我们要做的,就是通过代码把一个非线性的东西通过线性的东西表示
*/
#include<stdio.h>
//输出
void printA(int *a,int len)
{
int i;
for(i=0;i<len;i++)
printf("%4d",a[i]);
printf("\n");
}
//交换
void swap (int a[], int i, int j)
{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
//模拟一个二叉树堆排序的递归 先检查自己的结点,然后再去检查改变了结点的结点
//注意,这个函数只能检查当前结点以及改变了以后的子节点的二叉堆排序,并不是检查整个二叉树
void r_heap(int *a,int i,int len) //这里需要三个变量,len是用来表示递归退出条件的
{
int left = 2*i +1;
int right = 2*i +2;
int max = i;
if (left < len && a[left] > a[max] )
max = left;
if(right < len && a[right] > a[max] )
max = right;
if (max != i)
{
swap(a,i,max);
r_heap(a,max); //递归调用,应为子结点该表,所以要检查改变的
}
}
//堆排序
void heapsort(int *a,int len)
{
int have_child = len/2 -1; //满二叉树性质,非叶结点有(len/2 -1)个
int i;
for(i=have_child;i>;i++) //实现创建堆
{
r_heap(a,i,len);
}
for(i=len-1;i>0;i--) //不用i=0的的情况
{
swap(a,0,i);
r_heap(a,0,--len); //调整根节点
}
}
int main()
{
int a[10] = {9,8,7,6,5,4,3,2,1,0};
int len = sizeof(a)/sizeof(a[0]);
heapsort(a,len);
printA(a,len);
return 0;
}
归并排序
/*
2017年8月3日20:13:47
目的 : 归并排序
思路 :归并排序是吧一个数组,分成两部分,排好序在合并。
左边,右边的再分成两部分,实现递归。
需要注意的是,归并排序需要一个缓冲区,用来短暂保存合并后的数据。
*/
#include<stdio.h>
//输出
void printA(int *a,int len)
{
int i;
for(i=0;i<len;i++)
printf("%4d",a[i]);
printf("\n");
}
//交换
void swap (int a[], int i, int j)
{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
void merge(int *a,int left,int right,int mid,int *tmp)
{
int i = left;
int j = mid+1;
int k = 0 ;
while(i<=mid && j<=right)
{
if(a[i] <= a[j])
tmp[k++] = a[i++];
else
tmp[k++] = a[j++];
}
while(i<=mid)
tmp[k++] = a[i++];
while(j<=right)
tmp[k++] = a[j++];
k = 0;
for(i=left;i<=right;i++)
{
a[i] = tmp[k++];
}
}
void mergesort(int *a,int left,int right,int *tmp)
{
int mid = (left+right)/2;
if(left<right)
{
mergesort(a,left,mid,tmp);
mergesort(a,mid+1,right,tmp);
merge(a,left,right,mid,tmp);
}
}
int main()
{
int a[10] = {9,6,8,0,3,5,2,4,7,1};
int len = sizeof(a) / sizeof(a[0]);
int tmp[10];
mergesort(a,0,9,tmp);
printA(a,len);
return 0;
}
最后是快速排序,我写了两个,一个是以前写的,整体思路都是一样的,实现方法有一点不同。
/*
2017年8月2日17:29:42
目的 :快速排序
快速排序最重要的是实现找到排序数在当前排序的位置,然后递归排序前面的,在递归排序后面的
*/
#include<stdio.h>
void quikcsort(int *a,int low,int high); //快速排序
int find(int *a,int low,int high) ;
int main()
{
int a[10] = {34,3,46,21,24,46,83462,6,12385,23553};
quikcsort(a,0,10);
int i;
for(i=0;i<10;i++)
{
printf("%8d",a[i]);
}
printf("\n");
return 0;
}
void quikcsort(int *a,int low,int high)
{
int pos;
if(low<high)
{
pos = find(a,low,high);
quikcsort(a,low,pos-1);
quikcsort(a,pos+1,high);
}
return ;
}
int find(int *a,int low,int high) //找第一个元素所在数组的位置
{
int val = a[low];
while(low<high)
{
while(low<high && a[high]>=val) //大于等于最好,保证稳定性
high--;
a[low] = a[high];
while(low<high && val>=a[low])
low++;
a[high] = a[low];
}
a[low] = val;
return low;
}
//45 和 48 不能同时出现两个等于 不然就是死循环。 一个就可以
/*
2017年8月4日11:46:36
目的 :快速排序
思路 :快速排序的思路都是找到一个标志,然后找到标志所在数组中的位置,然后左边和右边的进行递归
*/
#include<stdio.h>
//输出
void printA(int *a,int len)
{
int i;
for(i=0;i<len;i++)
printf("%4d",a[i]);
printf("\n");
}
//交换
void swap (int a[], int i, int j)
{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
//找最后一个数在整个数组的位置
int find(int *a,int left,int right)
{
int tmp = a[right];
int index = left;
int i;
for(i=left;i<right;i++)
{
if( a[i] < tmp )
{
swap (a,i,index);
index++;
}
}
swap(a,index,right);
return index;
}
void quicksort(int *a,int left,int right)
{
if(left < right)
{
int pos = find(a,left,right);
quicksort(a,left,pos-1);
quicksort(a,pos+1,right);
}
}
int main()
{
int a[10] = {9,8,7,6,5,4,3,2,1,0};
int len = sizeof(a)/sizeof(a[0]);
quicksort(a,0,9);
printA(a,len);
return 0;
}