* 为了实现N个数的排序,将后面N-1个数依次插入到前面已排好的子序列中,
*假定刚开始第1个数是一个已排好序的子序列。经过N-1趟就能得到一个有序序列。
*****时间复杂度:最好情况O(n),最坏情况O(n^2),平均情况O(n^2).
*****空间复杂度:O(1)
*****稳定性:稳定
#include
#include
int main()
{
int n,i,j,temp;
int *p;
scanf("%d",&n);
p=(int *)malloc(sizeof(int)*n);
for(i=0;i
scanf("%d",&p[i]);
}
for(i=1;i
temp=p[i]; //临时存储待排序插入的树
for(j=i;j>0&&p[j-1]>temp;j--) //每次与前面的书比较至不满足条件或者已经全部比较了才结束
p[j]=p[j-1];
p[j]=temp;
}
for(i=0;i
printf("%d ",p[i]);
}
printf("\n");
return 0;
}
*<<折半插入排序>>
* 与直接插入排序不同的是,折半插入排序不是边比较边移动,而是将比较和移
*动操作分离出来,即先折半查找出元素的待插入位置,然后再统一地移动待插入位
*置之后的所有元素。不难看出折半插入排序仅仅是减少了比较的次数。
*****时间复杂度:O(n^2)
*****空间复杂度:O(1)
*****稳定性:稳定
#include
#include
int main()
{
int i,j,n,temp,low,high,mid;
int *p;
scanf("%d",&n);
p=(int *)malloc(n*sizeof(int));
for(i=0;i
scanf("%d",&p[i]);
}
for(i=1; i
{
temp=p[i];
low=0;
high=i-1;
while(low
{
mid=(low+high)/2;
if(p[i]
high=mid-1;
else
low=mid+1;
}
for(j=i-1;j>=low;j--) //将该数前面的从low/high开始的数全部后移
p[j+1]=p[j];
p[low]=temp; //将该数插入
}
for(i=0;i
printf("%d ",p[i]);
printf("\n");
return 0;
}
*<<希尔排序>>
希尔排序的实质就是分组插入排序,该方法又称缩小增量排序,因DL.Shell于1959年提出而得名。
该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)
分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)
时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况)
,效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。
以n=10的一个数组49, 38, 65, 97, 26, 13, 27, 49, 55, 4为例
第一次 gap = 10 / 2 = 5
49 38 65 97 26 13 27 49 55 4
1A 1B
2A 2B
3A 3B
4A 4B
5A 5B
1A,1B,2A,2B等为分组标记,数字相同的表示在同一组,大写字母表示是该组的第几个元素,
每次对同一组的数据进行直接插入排序。即分成了五组(49, 13) (38, 27) (65,49) (97,55)
(26, 4)这样每组排序后就变成了(13, 49) (27, 38) (49, 65) (55, 97) (4, 26),下同。
第二次 gap = 5 / 2 = 2.排序后
13 27 49 55 4 49 38 65 97 26
1A 1B 1C 1D 1E
2A 2B 2C 2D 2E
第三次 gap = 2 / 2 = 1
4 26 13 27 38 49 49 55 97 65
1A 1B 1C 1D 1E 1F 1G 1H 1I 1J
第四次 gap = 1 / 2 = 0 排序完成得到数组:
4 13 26 27 38 49 49 55 65 97
*/
#include
#include
#include
int main(){
int n,i,j,dk,temp;//dk是增量
int *p;
scanf("%d",&n);
p=(int *)malloc(n*sizeof(int));
for(i=0; i
scanf("%d",&p[i]);
for(dk=n/2; dk>0; dk/=2){ // 增量变化
for(i=dk; i
temp = p[i];
for(j=i; j-dk>=0 && p[j-dk]>temp; j-=dk) //对每个分组进行插入排序
p[j] = p[j-dk]; // 后移
p[j] = temp;
}
for(j=0; j
printf("%d ",p[j]);
printf("\n");
}
return 0;
}
----------------------------------交换排序------------------------------------
*<<冒泡排序>>
* 冒泡排序的基本思想是从后往前(或从前往后)两两比较相邻元素的值,若为
*逆序,则交换它们,直到序列比较完。我们称它为一趟冒泡。每一趟冒泡都会将一
*个元素放置到其最终位置上。
*****时间复杂度:最好情况O(n),最坏情况O(n^2),平均情况O(n^2)
*****空间复杂度:O(1)
*****稳定性:稳定
#include
#include
#include
int main()
{ int n,i,j,temp,swap=0;
int *p;
scanf("%d",&n);
p=(int *)malloc(n*sizeof(int));
for(i=0; i
scanf("%d",&p[i]);
for(i=n-1;i>0;i--){
swap=0; //表示序列是否已经有序。若是则不用再继续排序
for(j=0;j
if(p[j]>p[j+1]){
swap=1;
temp=p[j];
p[j]=p[j+1];
p[j+1]=temp;
}
}
for(j=0;j
printf("%d ",p[j]);
printf("\n");
if(swap==0) break;
}
return 0;
}
*<<快速排序>>
时间复杂度为O(nlgn)
//算法1
int quicksort(int *p,int n,int left,int right){
int pivot,temp,i,j;
if(left>=right)
return 0;
i=left;
j=right;
pivot=p[left];
while(i
while(ipivot)
j--;
while(i<=pivot)
i++;
if(i!=j){
temp=p[i];
p[i]=p[j];
p[j]=temp;
}
}
p[left]=p[i];
p[i]=pivot;
quicksort(p,left,i-1);
quicksort(p,i+1,right);
return 0;
}
//算法2
int quicksort(int *p,int left,int right){
int pivot,i,j;
if(left>=right)
return 0;
pivot=p[left];
i=left;
j=right;
while(i
while(ipivot)
j--;
p[i]=p[j];
while(i<=pivot)
i++;
p[j]=p[i];
}
p[i]=pivot;
for(i=0;i
printf("%d ",p[i]);
printf("\n");
quicksort(p,left,i-1);
quicksort(p,i+1,right);
return 0;
}
int main()
{
int n,i;
int *p;
scanf("%d",&n);
p=(int *)malloc(n*sizeof(int));
for(i=0; i
scanf("%d",&p[i]);
quicksort(p,0,n-1);
for(i=0;i
printf("%d ",p[i]);
printf("\n");
return 0;
}
----------------------------------选择排序-------------------------------
*<<简单选择排序>>
* 选择排序的算法思想很简单,假设序列为L[n],第i趟排序即从L[i...n]中选择
*关键字最小的元素与L(i)交换,每一趟排序可以确定一个元素的最终位置。经过n-1
*趟排序就可以使得序列有序了。
*****时间复杂度:始终是O(n^2)
*****空间复杂度:O(1)
*****稳定性:不稳定
#include
#include
#include
int main(){
int n,i,j,min,temp;
int *p;
scanf("%d",&n);
p=(int *)malloc(n*sizeof(int));
for(i=0; i
scanf("%d",&p[i]);
for(i=0;i
min=i; //假设在第i个至后面的所有值中其为最小值
for(j=i+1;j
if(p[j]
min=j;
if(min!=i){ //若实际最小的不是第i个,则交换
temp=p[min];
p[min]=p[i];
p[i]=temp;
}
}
return 0;
}
#include
#include
#include
//调整某个节点并递归调整其调整后可能出现的孩子大于父亲的问题
int adjustheap(int *p,int hn,int i){
int item;
int lchild=2*i+1;
int rchild=2*i+2;
int largest=i;
while(lchild
if(lchildp[largest]) //左孩子存在且大于父亲
largest=lchild;
if(rchildp[largest]) //右孩子存在且大于父亲
largest=rchild;
if(largest!=i){ //若父节点不是三者中最大的
item=p[i]; //将三者中最大的与父节点交换
p[i]=p[largest];
p[largest]=item;
i=largest; //最大的节点与父节点交换后可能导致以其为父节点的左右孩子比其大。则以其为父节点递归调整
lchild=2*i+1;
rchild=2*i+2;
}
else{
break;
}
}
return 0;
}
//建堆其实就是对无序序列数组对应的完全二叉树的所有节点进行调整形成一个大/小顶堆
int buildheap(int *p,int hn){
int i,begin;
begin=hn/2-1; //从最后一个节点的父节点开始
for(i=begin;i>=0;i--){
adjustheap(p,hn,i);
}
return 0;
}
int main()
{
int n,i,j,hn,item;
int *p;
scanf("%d",&n);
p=(int *)malloc(n*sizeof(int));
for(i=0; i
scanf("%d",&p[i]);
hn=n;
buildheap(p,hn); //将无序序列建成堆并调整所有节点使树成为大/小顶堆
while(hn>1){
item=p[0]; //将堆顶与最底一个节点交换
p[0]=p[hn-1];
p[hn-1]=item;
hn--;
adjustheap(p,hn,0); //将重新形成的无序序列的根节点与左右孩子进行调整
} //不用重新调整所有节点,因为最大/小值必定为根节点的左/右孩子
for(j=0;j
printf("%d ",p[j]);
printf("\n");
return 0;
}
-----------------------------------归并排序--------------------------------
*<<归并排序>>
一. 算法描述
合并有序数列的效率是比较高的,完全可以达到O(n)。
归并排序的基本思路就是先将待排序数组分成两组A,B,然后如果这两组组内的数据都是有序的,就可以
利用上面的逻辑(合并有序数列逻辑)很方便的将这两个有序数组数据再进行合并排序。
问题关键是如何让这两组组内数据有序呢?
可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经
达到了有序,然后再合并相邻的两个小组就可以了。
这样通过先递归的分解待排序数列,再合并数列就完成了归并排序的过程。实现归并排序。
二. 算法分析
平均时间复杂度:O(nlog2n)
空间复杂度:O(n) (用于存储有序子序列合并后有序序列)
稳定性:稳定
*/
//递归算法
#include
#include
#include
int meger(int *p,int low,int high){
int mid=(low+high)/2;
int left1=low;
int right1=mid;
int left2=mid+1;
int right2=high;
int *item,i,k;
item=(int *)malloc((high-low+1)*sizeof(int));//暂存合并后的序列
k=0;
while(left1<=right1&&left2<=right2)
{
if(p[left1]
item[k++]=p[left1++];
else
item[k++]=p[left2++];
}
while(left1<=right1)
item[k++]=p[left1++];
while(left2<=right2)
item[k++]=p[left2++];
for(i=0; i
p[low+i]=item[i]; //对有序的俩段序列进行合并
}
int meger_sort(int *p,int low,int high)
{
int mid;
if(low
{
mid=(low+high)/2; //递归不断分段,至每段长度都为一时返回
meger_sort(p,low,mid);
meger_sort(p,mid+1,high);
meger(p,low,high);
}
}
int main()
{
int n,i;
int *p;
scanf("%d",&n);
p=(int *)malloc(n*sizeof(int));
for(i=0; i
scanf("%d",&p[i]);
meger_sort(p,0,n-1);
for(i=0; i
printf("%d ",p[i]);
printf("\n");
return 0;
}
//非递归调用
#include
#include
#include
int _sort(int *p,int n,int start1,int start2,int num){
int *item;
item=(int *)malloc(n*sizeof(int));
int i=0,j=0,k=0;
while(i
if(p[start1+i]
item[k++]=p[start1+i];
i++;
}
else if(p[start1+i]==p[start2+i]){
item[k++]=p[start1+i];
i++;
j++;
}
else{
item[k++]=p[start2+j];
j++;
}
}
while(i
item[k++]=p[start1+i];
i++;
}
while(j
item[k++]=p[start2+j];
j++;
}
for(i=start1,j=0;i
p[i]=item[j];
}
int meger_sort(int *p,int n){
int num=1,i,j;
while(num
for(i=0;i
int start=2*num*i;
_sort(p,n,start,start+num,num);
}
num*=2;
}
return 0;
}
int main()
{
int n,i;
int *p;
scanf("%d",&n);
p=(int *)malloc(n*sizeof(int));
for(i=0; i
scanf("%d",&p[i]);
meger_sort(p,n);
for(i=0;i
printf("%d ",p[i]);
printf("\n");
return 0;
}
----------------------------------基数排序---------------------------
*<<基数排序>>
一. 算法描述
基数排序(以整形为例),将整形10进制按每位拆分,然后从低位到高位依次比较各个位。主要分为两个过程:
(1)分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中(比如53,个位为3,则放入3号桶中)
(2)收集,再将放置在0~9号桶中的数据按顺序放到数组中
重复(1)(2)过程,从个位到最高位(比如32位无符号整形最大数4294967296,最高位10位)
二. 算法分析
平均时间复杂度:O(dn)(d即表示整形的最高位数)
空间复杂度:O(10n) (10表示0~9,用于存储临时的序列)
稳定性:稳定
*/
//三. 算法实现
#include
#include
#include
#define MAX 10
//取得一个数第pos位的值
int getnumpos(int num,int pos){
int temp=1,i;
for(i=0;i
temp*=10;
return (num/temp);
}
int radixsort(int *p,int n){
int i,j,k,pos,count,index;
int *q[10]; //指针数组指向0~9号长度均为n的数组,分别存储对应位值的待排序数
for(i=0;i<10;i++){
q[i]=(int *)malloc((n+1)*sizeof(int));
q[i][0]=0; //0号单元不存待排序数,标示该数组中已存的个数
}
for(pos=1;pos
for(j=0;j
count=getnumpos(p[j],pos);
index=++q[count][0];
q[count][index]=p[j];
}
for(i=0,k=0;i<10;i++){ //收集到原来数组中
for(j=1;j<=q[i][0];j++)
p[k++]=q[i][j];
q[i][0]=0; //复位
}
}
}
int main()
{
int n,i;
int *p;
scanf("%d",&n);
p=(int *)malloc(n*sizeof(int));
for(i=0; i
scanf("%d",&p[i]);
radixsort(p,n);
for(i=0;i
printf("%d ",p[i]);
printf("\n");
return 0;
}