内部排序汇总

插入排序

 
直接插入排序

image

/* 直接插入排序 */
void insertSort(int a[], int n)
{
	int i,j;
	for (i=2;i<=n;i++) // 依次将a[i]插入到前面已排序序列
	{
		if (a[i]<a[i-1]) // 若a[i]小于其前驱,才需将a[i]插入有序表
		{
			a[0]=a[i]; // 复制为哨兵
			for (j=i-1;a[0]<a[j];--j) // 从后往前查找插入位置
			{
				a[j+1]=a[j]; // 向后挪位
			}
			a[j+1]=a[0]; // 复制到插入位置
		}
	}
}
 
希尔排序

直接插入排序的时间复杂度为O(n2),但若待排序序列为正序时,其时间效率可提高至O(n)。希尔排序从以下两点分析出发对直接插入排序进行改进:

  • 由于直接插入排序算法简单,则在n值很小时效率也比较高;
  • 若待排序序列按关键字“基本有序”时,直接插入排序的效率可大大提高。

image

/* 希尔排序 */
void shellSort(int a[], int n)
{
	// 对顺序表作希尔插入排序,本算法和直接插入排序相比,做了一下修改:
	// 1> 前后记录位置的增量为dk,不是1
	// 2> a[0]只是暂存单元,不是哨兵,当j<0时,插入位置已到
	int dk,i,j;
	for (dk=n/2;dk>=1;dk=dk/2) // 步长变化
	{
		for (i=dk+1;i<=n;i++)
		{
			if (a[i]<a[i-dk]) // 需将a[i]插入到有序增量子表
			{
				a[0]=a[i]; // 暂存在a[0]
				for (j=i-dk;j>0&&a[0]<a[j];j-=dk)
				{
					a[j+dk]=a[j]; // 记录后移,查找插入的位置
				}
				a[j+dk]=a[0]; // 插入
			}
		}
	}
}

交换排序

 
冒泡排序

image

/* 冒泡排序 */
void bubbleSort(int a[], int n)
{
	int i,j;
	for (i=0;i<n-1;i++) // 共有n-1趟排序
	{
		bool flag=false; // 表示本趟冒泡是否发生交换的标志
		for (j=0;j<n-i-1;j++) // 一次冒泡过程
		{
			if (a[j]>a[j+1])
			{
				swap(a[j],a[j+1]);
				flag=true;
			}
		}
		if (flag==false)
		{
			break; // 本趟遍历后没有发生交换,说明表已经有序
		}
	}
}
 
快速排序

参考之前文章:快速排序

image

// 一趟快速排序,划分 
int partition(int a[],int low,int high) 
{ 
    int i=low,j=high; 
    int x = a[i]; 
    while (i!=j) 
    { 
        while (a[j]>=x && i<j) j—; 
        if (i<j) { a[i]=a[j]; i++; } 
        while (a[i]<=x && i<j) i++; 
        if (i<j) { a[j]=a[i]; j—; } 
    } 
    a[i]=x; 
    return i; 
}

/* 快速排序 */
void quickSort(int a[],int low,int high)
{
    if (low<high)
    {
        int k = partition(a,low,high);
        quickSort(a,low,k-1);
        quickSort(a,k+1,high);
    }
}

选择排序

 
简单选择排序

image

/* 简单选择排序 */
void selectSort(int a[], int n)
{
	int i,j,min;
	for (i=0;i<n-1;i++) // 共进行n-1趟
	{
		min=i; // 记录最小元素位置
		for (j=i+1;j<n;j++) // 在a[i...n-1]中选择最小的元素
		{
			if (a[j]<a[min])
			{
				min=j; // 更新最小元素位置
			}
			if (min!=i)
			{
				swap(a[i],a[min]); // 最小元素与第i个位置交换
			}
		}
	}
}
 
堆排序

参考之前的文章:堆排序

/* 向下调整,即筛选 */
void adjustDown(int a[], int start, int n)
{
	// 根结点编号为1,对第start个元素进行调整
	a[0]=a[start]; // a[0]暂存
	for (int i=2*start;i<=n;i*=2) // 沿较大的子结点向下筛选
	{
		if (i<n&&a[i]<a[i+1])
		{
			i++; // 取较大的子结点的下标
		}
		if (a[0]>=a[i])
		{
			break; // 筛选结束
		}
		else
		{
			a[start]=a[i]; // 将a[i]调整到双亲结点上
			start=i; // 修改start,以便继续向下筛选
		}
	}
	a[start]=a[0]; // 被筛选结点的值放入最终位置
}

/* 堆排序 */
void heapSort(int a[], int n)
{
	for (int i=n/2;i>0;i--) // 1> 初始建堆,从i=n/2 --> 1,反复向下调整
	{
		adjustDown(a,i,n);
	}

	for (int j=n;j>1;j--) // 2> n-1趟的交换和建堆过程
	{
		swap(a[j],a[1]); // 输出堆顶元素(和堆底元素交换)
		adjustDown(a,1,j-1); // 把剩余的j-1个元素整理成堆
	}
}

二路归并排序

参考之前的文章:二路归并排序

161239480649942

// 一趟归并排序算法
int b[N];
void merge(int a[],int left,int mid,int right)
{
    // 表a的两段a[left..mid]和a[mid+1..right]各自有序,将它们合并成一个有序表
    for (int m=left;m<=right;m++)
        b[m] = a[m];                    // 将a中所有元素复制到b中
    for (int i=left,j=mid+1,k=i;i<=mid&&j<=right;k++)
    {
        if(b[i]<=b[j])                    // 比较b的左右两段中的元素
            a[k]=b[i++];                // 将较小值复制到a中
        else
            a[k]=b[j++];
    }
    while (i<=mid)      a[k++]=b[i++];    // 若第一个表为检测完,复制
    while (j<=right)  a[k++]=b[j++];    // 若第二个表为检测完,复制
    // 最后两个while循环只有一个会执行
}

/* 二路归并排序 */
void mergeSort(int a[],int left,int right)
{
    if (left < right)
    {
        int mid = (left+right)/2;    // 从中间划分两个子序列
        mergeSort(a,left,mid);        // 对左侧子序列进行递归排序
        mergeSort(a,mid+1,right);    // 对右侧子序列进行递归排序
        merge(a,left,mid,right);    // 归并
    }
}

总结

IMG_20150822_172030

posted @ 2015-06-07 09:55  枯桃  阅读(391)  评论(0编辑  收藏  举报