排序算法问题(一)

排序算法问题(二)堆排序,希尔排序

文章目录


在这里插入图片描述

1.直接选择排序

核心思想:(假设从小到大排序)

每次循环将子序列中最小的数放在第一位;将问题逐渐变为n-1个数比较大小的问题(递归思想);这种排序属于确定位置找最小元素的问题。
在这里插入图片描述
在这里插入图片描述

==算法解决:==如何将最小的数放在第一位?

1.用函数计算数组(c/c++)或列表的长度(python(len))
2.控制每一个元素跟后边的子序列比较
for(i=0;i<length-1;i++)或者for i in range(0,length-1)j//减一是因为最后一个数无子序列跟它比较结果已经出来了。
3.假设第一个元素都是最小的(记录下标)min=i
4.循环遍历子序列与假设的最小值比较
for(j=i+1;j<length;j++)或者for j in range(i+1,length)
5.如果假设的最小值大于子序列的中的值,min更改为该值的下标(min=j)。如果最小值的下标不是该循环的第一个元素则互换元素。
if(min!=i)
{t=a[min];
a[min]=a[i];
a[i]=t;
}
或者(python)
List[i],List[min]=List[min],List[i]

For instance:(常规实现)

== 1.记录下标法==

#include<stdio.h>
void main()//主函数
{
   int a[10];
   int i,j,t,min;//min记录最小值下标
   printf("请输入10个数字: \n");
   for(i=0;i<10;i++)
   scanf("%d",&a[i]);
   for(i=0;i<10-1;i++)//最后一个数无子序列,无需比较即得到结果
  	{
  	   min=i;
       for(j=i+1;j<10;j++)//不用和自己比较所以j=1
       //不能写成for(j=1;j<10-i;j++)因为min记录下标i,这样会使j无法对应下标
       if(a[i]>a[j])
       		min=j;
       if(min!=i)
      {
           t=a[i];
           a[i]=a[min];
           a[min]=t;
      }
    }
printf("排序后:\n");
for(i=0;i<10;i++)
printf("%4d",a[i]);
printf("\n");
 
}

2.直接换(此法跟冒泡法很类似,为了区分不建议使用)

#include<stdio.h>
void main()//主函数
{
   int a[10];
   int i,j,t;
   printf("请输入10个数字: \n");
   for(i=0;i<10;i++)
   scanf("%d",&a[i]);
   for(i=0;i<10-1;i++)
  	{
       for(j=i+1;j<10;j++)
       if(a[i]>a[j])//与冒泡法的不同之处在于冒泡是相邻两个元素比较大小互换。i实则就对应了最小值//不能写成for(j=1;j<10-i;j++)因为min记录下标i,这样会使j无法对应下标而冒泡法是前几个数的序列相邻两个数比较大小
      {
           t=a[i];
           a[i]=a[j];
           a[j]=t;
      }
    }
printf("排序后:\n");
for(i=0;i<10;i++)
printf("%4d",a[i]);
printf("\n");

 }


(递归实现直接选择排序算法)

在这里插入图片描述
在这里插入图片描述
思想:与普通做法相同,普通做法本就包含递归思想,这里只不过将第一个for循环的形式改为递归实现。

#include<stdio.h>
#include<stdlib.h>
#define N 10
void SelectionSort(int* a,int n,int i)
{
    if(i>=n-1)
    {
        return;
    }
    else{
        int temp,j;
        temp=i;
        for(j=i+1;j<n;j++)
        {
            if(a[j]<a[temp])
                temp=j;
        }
        if(temp!=i)
        {
            int m;
            m=a[temp];
            a[temp]=a[i];
            a[i]=m;
        }
        SelectionSort(a,n,i+1);
    }
}
 
int main()
{
    int a[N],i,j,temp;
	printf("请输入10个数:\n");
	for(i=0;i<N;i++)
	{
		scanf("%d",&a[i]);
	}
SelectionSort(a,N,0);
  printf("排好序的数为:\n"); 
    for(i=0;i<N;i++)
        printf("%d  ",a[i]);
    printf("\n");
}



2.冒泡排序(从小到大)

核心思想:相邻两个元素比较大小并进行互换,一轮排序后最大的在最后(即最大的泡浮出水面)

在这里插入图片描述
剩下的子序列再两两比较,该循环结束后该子序列的最大值到次末尾。

For instance:

#include<stdio.h>
int main()//主函数
{
   int a[10];
   int i,j,t,flag;//min记录最小值下标
   printf("请输入10个数字: \n");
   for(i=0;i<10;i++)
   scanf("%d",&a[i]);
   for(i=0;i<10-1;i++)
  	{
		flag=0;//假设没有元素交换
       for(j=0;j<10-i-1;j++)//不能写成for(j=0;j<10-i;j++)原因在下一条语句
       if(a[j]>a[j+1])//即第一次循环的j+1=10,造成数组溢出
      {
           t=a[j];
           a[j]=a[j+1];
           a[j+1]=t;
		   flag=1;
      }
	   if(flag==0)//节省时间提前退出
		   break;
    }
printf("排序后:\n");
for(i=0;i<10;i++)
printf("%4d",a[i]);
printf("\n");
return 0;
 }


与直接选择排序的区别:相邻两个元素间比较大小,一轮排序后确认最大值在最后。而直接选择排序一轮比较后确认的最小值在前面,这就决定了为什么在第二个for循环两种排序j取值不同的原因。

3.插入排序(从小到大)

==核心思想:==默认第一个有序,依次提取后面的数(放于暂存空间)跟前面的有序数据比较,如果比前面的数据小,则有序数据往后移动,否则在特定位置插入该元素。类似斗地主抓牌的时候整理牌的过程。

在这里插入图片描述

#include<stdio.h>
void InsertionSort(int *num,int n) 
 {
  	int i,j, temp = 0;
  	for(i = 1;i<n;i++)//从第二个数开始和前面比较
  	{
      temp = num[i];//从待插入组取出第一个元素放到到暂存空间
		for(j=i;j>0&&temp<num[j-1];j--)//该元素依次跟前面的数比较,如果小于前面的数则前面的有序数依次往后移动
		{
			num[j]=num[j-1];//
		}
		num[j]=temp;//该元素插入到合适的位置
	}
 }
  int main() 
  {
  	int i;
  	int num[8];
	printf("请输入8个数据:\n");
	for(i=0;i<8;i++)
		scanf("%d",&num[i]);
  	InsertionSort(num,8);
  	for(i=0;i<8;i++)
    	printf("%d ",num[i]);
  	return 0;
  }

4.快速排序(分治思想)

分治思想:将一个大问题拆分为足够小的小问题(递归思想),再将小问题求解,然后自底向上合并得到大问题的解。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

核心思想:分治思想是均分,而快排根据哨兵的位置分,而最初哨兵位置的选取,决定了算法的性能的高低,一般哨兵最终位置在数列的中间性能最佳,即均分两个子序列,因此哨兵的位置因采取随机选取的方式较好,正因如此快速排序可以有多种优化方式。(i,j相遇时就是哨兵的最终位置),分完之和对两个子序列进行排序,排完后不需要合并。

1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数(分治)。

快速排序(挖坑版)

特定选取某个元素作为哨兵。(第一个位置)

For instance:

#include<stdio.h>
//快速排序
#define N 5
int quick_sort(int s[], int l, int r)
{
        int i = l, j = r, x = s[l];
        while (i < j)
        {
            while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
				j--;  
            if(i < j) 
				s[i++] = s[j];//将小于x的数放于左边
            while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
				i++;  
            if(i < j) 
				s[j--] = s[i];//将大于x的数放于右边
        }
        s[i] = x;
		return i;
}
//分治
void quick_sort1(int s[], int l, int r)
{
	if (l < r)
    {
		int i =quick_sort(s, l, r);//先成挖坑填数法调整s[]
		quick_sort1(s, l, i - 1); // 递归调用 
		quick_sort1(s, i + 1, r);
	}
}
int main(){
	int num[N],left=0,rigth=N-1,i,x;
	x=N;
	printf("请输入%d个整数!\n",x);
	for(i=0;i<N;i++)
		scanf("%d",&num[i]);
	quick_sort1(num,left,rigth);
	for(i=0;i<N;i++)
		printf("%d  ",num[i]);
}


参考文献
用栈解决递归

快速排序(交换版)

#include<stdio.h>
void Swap(int arr[], int low, int high)
{
    int temp;
    temp = arr[low];
    arr[low] = arr[high];
    arr[high] = temp;
}
 
int Partition(int arr[], int low, int high)
{
    int base = arr[low];
    while(low < high)
    {
        while(low < high && arr[high] >= base)
        {
            high --;
        }
        Swap(arr, low, high);
        while(low < high && arr[low] <= base)
        {
            low ++;
        }
        Swap(arr, low, high);
    }
    return low;
}
 
void QuickSort(int arr[], int low, int high)
{
    if(low < high)
    {
        int base = Partition(arr, low, high);
        QuickSort(arr, low, base - 1);
        QuickSort(arr, base + 1, high);
    }
}
 
int main()
{
    int n;
    scanf("%d\n",&n);
    int arr[n];
    int i , j;
    for(i = 0; i < n; i ++)
    {
        scanf("%d",&arr[i]);
    }
    printf("\n");
    QuickSort(arr, 0, n-1);
    for(j = 0; j < n; j ++)
    {
        printf("%4d",arr[j]);
    }
    return 0;
}

5.归并排序

核心思想:采用分治思想将数据先递归的分解,再合并数数据就完成了归并排序。将数据分成两组,以此类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。

For instance:

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define N 5
//将有二个有序数列a[first...mid]和a[mid...last]合并
void mergearray(int a[], int first, int mid, int last, int temp[])
{
	int i = first, j = mid + 1;
	int m = mid,   n = last;
	int k = 0;
	
	while (i <= m && j <= n)
	{
		if (a[i] <= a[j])
			temp[k++] = a[i++];
		else
			temp[k++] = a[j++];
	}
	
	while (i <= m)
		temp[k++] = a[i++];
	
	while (j <= n)
		temp[k++] = a[j++];
	
	for (i = 0; i < k; i++)
		a[first + i] = temp[i];
}
void mergesort(int a[], int first, int last, int temp[])
{
	if (first < last)
	{
		int mid = (first + last) / 2;
		mergesort(a, first, mid, temp);    //左边有序
		mergesort(a, mid + 1, last, temp); //右边有序
		mergearray(a, first, mid, last, temp); //再将二个有序数列合并
	}
}
 
bool MergeSort(int a[], int n)
{
	int *p = new int[n];
	if (p == NULL)
		return false;
	mergesort(a, 0, n - 1, p);
	delete[] p;
	return true;
}
int main()
{
    int arr[N];
    int i ,x, j;
	x=N;
	printf("请输入%d个整数:\n",x);
    for(i = 0; i < N; i ++)
    {
        scanf("%d",&arr[i]);
    }
    printf("\n");
    MergeSort(arr,  N);
    for(j = 0; j < N; j ++)
    {
        printf("%4d ",arr[j]);
    }
    return 0;
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值