您的位置:首页 > 理论基础

计算机算法设计与分析——排序(递归算法)

2020-02-02 14:29 1136 查看

1. 简单选择排序

基本思想:每一趟在n-i+1(i=1,2,…,n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。具体来说,假设长度为n的数组arr,要按照从小到大排序,那么先从n个数字中找到最小值min1,如果最小值min1的位置不在数组的最左端(也就是min1不等于arr[0]),则将最小值min1和arr[0]交换,接着在剩下的n-1个数字中找到最小值min2,如果最小值min2不等于arr[1],则交换这两个数字,依次类推,直到数组arr有序排列。算法的时间复杂度为O(n^2)。

void SelectSort(int a[], int n, int i)
{
int j, k;
if (i == n - 1)  //表示已经选择到最后一个值,无序排序
{
return;
}
else
{
k = i;  //k记录a[i..n-1]中最小元素的下标
for (j = i + 1; j<n; j++)  //在a[i..n-1]中找出最小元素
{
if (a[j] < a[k])
{
k = j;
}
}
if (k != i)  //若最小元素不是a[i]
{
swap(a[i], a[k]);  //交换
}
SelectSort(a, n, i + 1);
}
}

百度百科:简单选择排序

2.冒泡排序

基本思想:首先从数组的第一个元素开始到数组最后一个元素为止,对数组中相邻的两个元素进行比较,如果位于数组左端的元素大于数组右端的元素,则交换这两个元素在数组中的位置,此时数组最右端的元素即为该数组中所有元素的最大值。接着对该数组剩下的n-1个元素进行冒泡排序,直到整个数组有序排列。
f(a,n,i)=不做任何事情,算法结束           当i=n-1
f(a,n,i)=对a[i…n-1]元素序列,从a[n-1]开始
    进行相邻元素比较;            否则
    若相邻两元素反序则将两者交换;
    若没有交换则返回,否则执行f(a,n,i+1);

// 冒泡排序
void BubbleSort(int a[], int n, int i)
{
int j;
bool exchange;
if (i == n - 1)  //满足递归出口条件
{
return;
}
else
{
exchange = false;  //置exchange为false
for (j = n - 1; j > 1; j--)
{
if (a[j] < a[j - 1])  //当相邻元素反序时
{
swap(a[j], a[j - 1]);
exchange = true;  //发生交换置exchange为true
}
}
if (exchange == false)  //未发生交换时直接返回
{
return;
}
else  //发生交换时继续递归调用
{
BubbleSort(a, n, i + 1);
}
}
}

百度百科:冒泡排序

3.快速排序

基本思想:①先从数列中取出一个数作为基准数。②分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。③再对左右区间重复第二步,直到各区间只有一个数。

void QuickSort(int a[], int s, int t)//对a[s..t]元素序列进行递增排序
{
if (s < t)//序列内至少存在2个元素的情况
{
int i = Partition(a, s, t);
QuickSort(a, s, i - 1);//对左子序列递归排序
QuickSort(a, i + 1, t);//对右子序列递归排序
}
}
// 快速排序
void Partition(int a[], int left, int right)//划分算法
{
int i = left;
int	j = right;
int key = a[left];//用序列的第1个记录作为基准
while (i != j)//从序列两端交替向中间扫描,直至i=j为止
{
while (j > i&&a[j] >= key)
{
j--;//从右向左扫描,找到第1个关键字小于tmp的a[j]
}
a[i] = a[j];//将a[j]前移到a[i]的位置
while (i < j&&a[i] <= key)
{
i++;//从左往右扫描,找到第1个关键字大于tmp的a[i]
}
a[j] = a[i];//将a[i]后移到a[j]的位置
}
a[i] = key;
}

百度百科:快速排序

4.自底向上的归并排序

基本思想:数组中先一个一个归并成两两有序的序列,两两有序的序列归并成四个四个有序的序列,然后四个四个有序的序列归并八个八个有序的序列,以此类推,直到,归并的长度大于整个数组的长度,此时整个数组有序。需要注意的是数组按照归并长度划分,最后一个子数组可能不满足长度要求,这个情况需要特殊处理。

void MergePass(int a[],int length,int n)  //一趟二路归并排序
{
int i;
for (i = 0; i + 2 * length - 1 < n; i = i + 2 * length)  //归并length长的两相邻子表
Merge(a, i, i + length - 1, i + 2 * length - 1);
if (i + length - 1 < n)  //余下两个子表,后者长度小于length
Merge(a, i, i + length - 1, n - 1);  //归并这两个子表
}

void Merge(int a[], int low, int mid, int high)  //a[low..mid]和a[mid+1..high]->a[low..high]
{
int *tmpa;
int i = low, j = mid + 1, k = 0;
tmpa = (int *)malloc((high - low + 1)*sizeof(int));
while (i <= mid&&j <= high)
if (a[i] <= a[j])  //将第1子表中的元素放入tmpa中
{
tmpa[k] = a[i];
i++;
k++;
}
else  //将第2子表中的元素放入tmpa中
{
tmpa[k] = a[j];
j++;
k++;
}
while (i <= mid)  //将第1子表余下部分复制到tmpa
{
tmpa[k] = a[i];
i++;
k++;
}
while (j <= high)  //将第2子表余下部分复制到tmpa
{
tmpa[k] = a[j];
j++;
k++;
}
for (k = 0, i = low; i <= high; k++, i++)  //将tmpa复制回a中
a[i] = tmpa[k];
free(tmpa);  //释放tmpa所占内存空间
}

void MergeSort(int a[], int n)  //二路归并算法
{
int length;
for (length = 1; length < n; length = 2 * length)
MergePass(a, length, n);
}

百度百科:归并排序

  • 点赞
  • 收藏
  • 分享
  • 文章举报
可一z可再 发布了18 篇原创文章 · 获赞 1 · 访问量 241 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: