Educoder头歌数据结构-十大经典排序算法

本文详细介绍了冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序以及基数排序等十个常见数据结构排序算法的实现过程,通过代码实例展示每种算法的工作原理和操作步骤,并附带关键操作的输出。

数据结构-十大经典排序算法

如果被平台自动设置成VIP可见,评论一下我看到了就给放开,没招了

"不定时更新中"
"还未写完,但可全部通关"
"仅供参考"

第1关:冒泡排序

void sort_array(int *arr, int n)
//  编程实现《冒泡排序算法》:将乱序序列arr转化为升序序列
//  函数参数:乱序整数数组arr 数组长度
//  要求输出:调用print_array(int *arr, int n)输出前三次冒泡操作后的序列,以及最终的升序序列
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
    /*
    int i ,j;
    for(i=0;i<n-1;i++)//进行 n-1 次
    {
        for(j=0;j<n-i-1;j++)//每次 n-i-1 轮 
            if(arr[j]>arr[j+1])
            {//前>后  大的数后移
                int temp   =arr[j];
                    arr[j]    = arr[j+1];
                    arr[j+1] = temp; 
            }
        if(i<3)
            print_array(arr, n); //前三次输出  
    }
       
       print_array(arr, n);          
    */
    //优化:
    int i ,j;
    int flag ;

    for(i=0;i<n-1;i++)//进行 n-1 次
    {
        flag = 0;//交换标识

        for(j=0;j<n-i-1;j++)//每次 n-i-1 轮 
            if(arr[j]>arr[j+1])
            {//前>后  大的数后移
                int temp   =arr[j];
                    arr[j]    = arr[j+1];
                    arr[j+1] = temp; 
                    flag  = 1;
            }
        //-----------------------------
            if(flag==0)
                break;
            /*
                如果此时flag == 0 
                说明当前轮没有发生交换
                即;此时当前数列已经"有序"
            */
        //-----------------------------
            if(i<3)
                print_array(arr, n); //前三次输出  
    }
       print_array(arr, n);    
    /********** End **********/
}

第2关:选择排序

void sort_array(int *arr, int n)
//  编程实现《选择排序算法》:将乱序序列arr转化为升序序列
//  函数参数:乱序整数数组(无重复元素) 数组长度
//  要求输出:调用print_array(int *arr, int n)输出前三次选择操作后的序列,以及最终的升序序列
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
     int i ,j,min;
     int flag = 0,temp=0;
    for(i=0;i<n-1;i++)
    {
        min = arr[i];//设定最小值
        for(j=i+1;j<n;j++)
            if(min>arr[j])
                {//如果出现更小的值,保存更小值的下标
                    min = arr[j];
                    flag = 1;
                    temp=j;
                }

       if(flag==1)//"flag==1"说明找到更小的值,即下标发生了变化 -> 交换
       {
          int t = arr[i];
          arr[i]  = arr[temp];
          arr[temp] = t;
          flag = 0 ;
       }

        if(i<3)
            print_array(arr, n); //前三次输出  
    }
       
       print_array(arr, n);     
    
    /********** End **********/
}

第3关:插入排序

void sort_array(int *arr, int n)
//  编程实现《插入排序算法》:将乱序序列arr转化为升序序列
//  函数参数:乱序整数数组(无重复元素) 数组长度
//  要求输出:调用print_array(int *arr, int n)输出前三次插入操作后的序列,以及最终的升序序列
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
    
   	int i ,j ,temp;
	for(i =1;i<n;i++)
  	{
      if(arr[i]<arr[i-1])
      {
        temp = arr[i];
        for(j=i-1;temp<arr[j]&&j!=-1;j--)//注意此处的  !=-1           
             arr[j+1] = arr[j];
             
             
        arr[j+1] =temp;
      }
      if(i<4)
        print_array(arr, n);
  	}
     print_array(arr, n);  

     
    /********** End **********/
}

第4关:希尔排序


void sort_array(int *arr, int n)
//  编程实现《希尔排序算法》:将乱序序列arr转化为升序序列
//  函数参数:乱序整数数组 数组长度
//  要求输出:调用print_array(int *arr, int n)输出三遍增量排序操作后的序列,以及最终的升序序列
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
	int i = 0,t=0;
	int key = 0;
	int end = 0;
	int Gap[4] = {5,2,1,-1};//最后的-1为终止条件
    //如果需要跟给增量,直接在这里给
	int gap = Gap[t];//给增量
	while (gap > 0)
	{
		for (i = gap; i < n; i++)
		{
			key = arr[i];
			end = i - gap;
			while (end >= 0 && key<arr[end])
			{
				arr[end + gap] = arr[end];
				end=end-gap;
			}
			arr[end + gap] = key;
		}
		
		print_array(arr, n);
		t++;
		gap=Gap[t];
	
	}
	print_array(arr, n);
    /********** End **********/
}

第5关:归并排序


int* merge_array(int *arr1, int n1, int* arr2, int n2)
//  编程实现两个有序数组arr1和arr2合并
//  函数参数:有序数组arr1 数组arr1长度 有序数组arr2 数组arr2长度
//  函数返回值:返回从小到大排序后的合并数组
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
	//定义
	int arr3_length =  n1 + n2;
    int *arr3 = (int *)malloc(sizeof(int)*arr3_length);//注解①
	 
	int i=0 , j=0,t=0;
	//比较两个顺序表中的值,并将小的值放入LC中,当其中一个表比较完成后
	while(i<n1&&j<n2)
		{
			if(arr1[i]<=arr2[j])
				arr3[t++] = arr1[i++];
			else
				arr3[t++] = arr2[j++];	
		}


	//直接将另一个未比较完成的表中的剩余值全部放到LC中

	if(i==n1)
		{
			while(t<arr3_length)
				arr3[t++] = arr2[j++];	
		}
	else
		{
			while(t<arr3_length)
			arr3[t++] = arr1[i++];
		}
	return arr3;
/*
	注解①:
		1.此处必须使用malloc函数动态分配内存
		  若使用int arr3[arr3_length]的方式
		  分配内存,则当该函数结束,此空间已经
		  归并好的数据将被程序释放,在另一个
		  函数中接收到的将是一堆垃圾值 
	
		2.通常来说动态分配内存很少失败,但 
		为使程序更加健壮,可以增加以下代码

		if(arr3==NULL)
			return NULL; //动态分配空间失败 
	
*/	
    /********** End **********/
}

int* merge_sort(int *arr, int n)
//  基于merge_array函数编程实现归并排序:自上而下的递归方法
//  函数参数:有序数组arr 数组arr长度
//  函数返回值:返回从小到大排序后的数组
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
    int mid ;
    int left = 0 ,right = n;//注解① 
  
	mid = (left+right)/2;
	
    if(right!=1)//注解② 
    {
		//从mid将数组分成两部分 
        int *Arr_1 = &arr[left],*Arr_2 = &arr[mid];

		//左侧 
        Arr_1 = merge_sort(Arr_1,mid);
        //右侧 
        Arr_2 = merge_sort(Arr_2,right-mid);
        
        //合并 
        arr = merge_array(Arr_1,mid,Arr_2,right-mid);

    }
    return arr;
    
/*
	注解①: 
		此处 right==n 
	
	注解②:
	    1.	当right==1时说明"小数组"的长度为1
	    	即:不可在分 
	 	
	    2.	也可使用
			if(mid!=0)
				因为:left一定等于0,且right==1
				故:mid = (0+1)/2 = 0; 
			
		3.	此处若换成
			if(left<right)是错误的
			因为按理说最后一次 left = 0,right = 1,
			此时 left<right始终成立,将一直递归下去,
			不会终止		   
*/
	   
    /********** End **********/
}


第6关:快速排序


int partition_array(int *arr ,int l,int r)
// 编程实现arr[l, r]分区:选定一个基准,左边比基准小,右边比基准大
// 返回基准所处位置
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
    int temp = arr[l];//临时空间,存放"枢轴"
	while(l<r)//终止条件 
	{        
		while((l<r)&&arr[r]>=temp)//"大"数在高位不动
			r--;//注解①
		arr[l] = arr[r];//"小"数在高位移动

		while((l<r)&&arr[l]<=temp)
			l++;
		arr[r] = arr[l];

    }
    arr[l] = temp;
    return l;
    /*
    注解①
	注意:	此处的两个内部的while循环均再次进行了判断
				low<high 判断,因为在比较的过程中,如果未发生
				值的覆盖,则low/high将一直移动,此过程中就可能
				导致 循环不在满足low<high ;
*/
    /********** End **********/
}

int* quick_sort(int *arr, int l, int r)
//  基于partition_array函数编程实现快速排序:自上而下的递归方法
//  函数参数:有序数组arr 初始l=0,r=n-1
//  函数返回值:返回从小到大排序后的数组
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
    int pos = partition_array(arr,l,r);

    if(l<r)
    {
        if(l<pos-1)
			arr = quick_sort(arr,l,pos-1);
        if(pos+1<r)
            arr = quick_sort(arr,pos+1,r);
    }
    return arr;
    /********** End **********/
}

第7关:堆排序


void adjustHeap(int *arr, int param1, int j)
// 编程实现堆的调整
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
    int temp;
    if(j<param1)
	{
		int max=j;//根结点
		int s1=2*j+1;//左子节点
		int s2=2*j+2;//右子结点
		//找出最大结点
		if(arr[s1]>arr[max]&&s1<param1)
			max=s1;
		if(arr[s2]>arr[max]&&s2<param1)
			max=s2;
		//交换最大子节点到根结点并做递归
		if(max!=j)
		{
			
            temp     = arr[max];
            arr[max] = arr[j];
            arr[j]   = temp; 
			
            adjustHeap(arr,param1,max);		
		}
	}
    /********** End **********/
}

int* heap_sort(int *arr, int n)
//  基于adjustHeap函数编程实现堆排序
//  函数参数:无序数组arr 数组长度n
//  函数返回值:返回从小到大排序后的数组
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
    //创建初始堆
    int i,temp;
    int last=n-1;				//最后一个子结点位置
	int parent=(last-1)/2;		//最后一个子结点的父结点
	for(int i=parent;i>=0;i--)	
	{
		adjustHeap(arr,n,i);		//从最后一个父结点开始做最大堆调整
	}
    for(int i=n-1;i>=0;i--)//依次将最大堆的根结点(最大值)取出
	{
	//将最大堆的根(最大值)换到最后
        temp   = arr[i];
        arr[i] = arr[0];
        arr[0] = temp;

	//除去最大值,对交换后的二叉树做最大堆调整,使二叉树根结点始终为最大值	
		adjustHeap(arr,i,0);		
	}

    return arr;

    /********** End **********/
}


第8关:计数排序


void sort_array(int *arr, int n)
//  编程实现《计数排序算法》
//  函数参数:乱序整数数组 数组长度
//  要求输出:调用print_array(int *arr, int n)输出:
//  每一行一个元素及其个数(升序),如 1 1
//  以及最终的升序序列
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
     //查找最大最小值
    
    int MAX =arr[0],MIN=arr[0], t =0 ;;
 
  	int i ;
  	//寻找数组中最大最小值 
    for(i=0;i<n;i++)
        {
            if(arr[i]>=MAX)
                    MAX = arr[i];       
             if(arr[i]<=MIN)
                    MIN = arr[i];
        }

	//生成统计数组,并清空数据 
    int Arr_2[MAX] ;
    int  j=0;
    while(j<=MAX)
    {
    		Arr_2[j] =0;
    		j++; 
	}
    for( i=0;i<n;i++)
       	 Arr_2[arr[i]]++;//统计 
       	 
    for( i = MIN;i<=MAX;i++)
        {
           int temp = Arr_2[i];//保存arr数组中每个数出现的次数
           while(Arr_2[i]!=0) 
            {
                arr[t] = i;//还原数组 
                t++;
                Arr_2[i]--;
            }
        	if(temp!=0)
           	printf("%d %d\n",i,temp);
          
        }
    
    print_array(arr,n);//输出 

    /********** End **********/
}

第9关:桶排序

int* sort_array(int *arr, int n)
//  编程实现《桶排序算法》
//  函数参数:乱序整数数组 数组长度
//  函数返回值:返回从小到大排序后的数组
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
	
   	//寻找数组中元素的最大值
	int i,j,MAX = arr[0],MIN = arr[0],Num = 10;
	//Num --桶的个数  -- 没多一个桶,可容纳的待排序的数字就可以大10
	
	int bucketEle[10] ;//桶中情况 
	
	//寻找数组中最大最小值 
    for(i=0;i<n;i++)
        if(arr[i]>=MAX)
                MAX = arr[i];       
        else if(arr[i]<=MIN)  
        		MIN = arr[i];
	
	int len =15;//单个桶的长度 
	int bucketArry [Num][len];
	
	//清空桶
	for(i=0;i<Num;i++)
		{
			bucketEle[i]  = 0; 
			for(j=0;j<len;j++)
				bucketArry[i][j]=0;
		}
	
	//数据入桶
	for(i=0;i<n;i++) 
	{
		int  subScript_1 = arr[i]/10;//寻找该入哪个桶	
		bucketArry[subScript_1][bucketEle[subScript_1]] = arr[i];
		bucketEle[subScript_1]++;//统计桶中元素的个数
			
	}
	
	
	//冒泡排序【对每一个单独的桶进行排序】
	int temp,f;
	for(temp=0;temp<Num;temp++)//二维数组的第几行 
		{
			int length = bucketEle[temp];
			for(i=0;i<length-1;i++)
				{
					for(j=0;j<length-i-1;j++)
						{
							if(bucketArry[temp][j]>bucketArry[temp][j+1])
							{
								f = bucketArry[temp][j];
								bucketArry[temp][j] = bucketArry[temp][j+1];
								bucketArry[temp][j+1] = f;
							}
						}
				}
		}
			
	int t=0,k=0;
	//数据整合
	for(i=0;i<Num;i++)
	{
		if(bucketEle[i]!=0)//当前桶不空
		{
			while(k<bucketEle[i]) 
			{
				arr[t] = bucketArry[i][k];
				
				t++;//总元素
				k++; 
			}
		} 
		k=0;
	}
		 
	
   return arr;

    /********** End **********/
}



第10关:基数排序

没写呢
    直接使用"计数排序"代码可过

int* sort_array(int *arr, int n)
//  编程实现《基数排序算法》
//  函数参数:乱序整数数组 数组长度
//  函数返回值:返回从小到大排序后的数组
{
    // 请在这里补充代码,完成本关任务
    /********** Begin *********/
      int MAX =arr[0],MIN=arr[0], t =0 ;
 
  	int i ;
  	//寻找数组中最大最小值 
    for(i=0;i<n;i++)
        {
            if(arr[i]>=MAX)
                    MAX = arr[i];       
             if(arr[i]<=MIN)
                    MIN = arr[i];
        }
        

	//生成统计数组,并清空数据 
    int Arr_2[MAX] ;
    int  j=0;
    while(j<=MAX)
    {
    		Arr_2[j] =0;
    		j++; 
	}
  
  
    for( i=0;i<n;i++)
       	 Arr_2[arr[i]]++;//统计 
       	 
    for( i = MIN;i<=MAX;i++)
        {
        //   int temp = Arr_2[i];//保存arr数组中每个数出现的次数
           while(Arr_2[i]!=0) 
            {
                arr[t] = i;//还原数组 
                t++;
                Arr_2[i]--;
            }
        	//if(temp!=0)
           //	printf("%d %d\n",i,temp);
          
        }
    
    return arr;//输出 
    
    /********** End **********/
}



22春"计算机科学与技术"专业《计算方法》在线作业答案参考 1. 一个有n个结点的图,最多有( )个连通分量。 A.0 B.1 C.n-1 D.n 参考答案:D 2. 迭代法的优点是算法简单,因而编制程序比较容易。( ) 迭代法的优点是算法简单,因而编制程序比较容易。( ) A、错误 B、正确 参考答案:B 3. 已知一列数{8,9,7,4,1,2},使用简单选择排序法对其按照升序进行排列,第0趟比较之后数列为( ) A.8,9,7,4,1,2 B.1,9,7,4,8,2 C.8,7,4,1,2,9 D.1,2,8,9,7,4 参考答案:B 4. 在C语言中字符串的文件是string.h。( ) A.错误 B.正确 参考答案:B 22春"计算机科学与技术"专业《计算方法》在线作业一答案参考9全文共5页,当前为第1页。5. 依据3个样点(0,1),(1,2)(2,3),其插值多项式p(x)为( )。 依据3个样点(0,1),(1,2)(2,3),其插值多项式p(x)为( )。 A、x B、x+1 C、x-1 D、x+2 参考答案:B 22春"计算机科学与技术"专业《计算方法》在线作业一答案参考9全文共5页,当前为第1页。 6. 对于二分查找,表必须有序且表中数据必须是整型,实型或字符型。( ) A.错误 B.正确 参考答案:A 7. 按"先进后出"原则组织数据的数据结构是队列。( ) A.错误 B.正确 参考答案:A 8. 执行memset(s,'a',4)后,s的值为( )。 A."aaaa" B."a4" C."4a" D."eeee" 参考答案:A 9. 基于"使残差的平方和"为最小的准则来选取拟合曲线的方法称为曲线拟合的最小二乘法。( ) 基于"使残差的平方和"为最小的准则来选取拟合曲线的方法称为曲线拟合的最小二乘法。( ) A、错误 B、正确 参考答案:B 22春"计算机科学与技术"专业《计算方法》在线作业一答案参考9全文共5页,当前为第2页。10. 递归算法的执行过程分( )和( )两个阶段。 A.递归 B.递推 C.回归 D.回溯 参考答案:BC 22春"计算机科学与技术"专业《计算方法》在线作业一答案参考9全文共5页,当前为第2页。 11. 下列叙述中正确的是( )。 A.线性表的链式存储结构与顺序存储结构所需要的存储空间是相同的 B.线性表的链式存储结构所需要的存储空间一般要多于顺序存储结构 C.线性表的链式存储结构所需要的存储空间一般要少于顺序存储结构 D.上述三种说法都不对 参考答案:B 12. 顺序结构、选择结构、循环结构三种结构共同特点是( ) A.只有一个入口 B.只有一个出口 C.结构内的每一部分都有机会被执行到(不存在死语句) D.结构内不存在死循环(永远执行不完的循环) 参考答案:ABCD 13. 下列排序方法中,哪一个是稳定的排序方法?( ) A.直接选择排序 B.二分法插入排序 C.希尔排序 D.快速排序 参考答案:B 14. 冒泡排序是一种不稳定排序方法。( ) A.错误 B.正确 参考答案:A 22春"计算机科学与技术"专业《计算方法》在线作业一答案参考9全文共5页,当前为第3页。15. 通过点(x ,y ),(x ,y )的拉格朗日插值基函数l (x ),l (x )满足( )。 通过点(x ,y ),(x ,y )的拉格朗日插值基函数l (x ),l (x )满足( )。 A、l (x )=0,l (x )=0 B、l (x )=0,l (x )=1 C、l (x )=1,l (x )=0 D、l (x )=1,l (x )=1 参考答案:D 22春"计算机科学与技术"专业《计算方法》在线作业一答案参考9全文共5页,当前为第3页。 16. 下列说法错误的是( ) A.使用高级计算机语言,如C、C++、Java,编写的程序,都需要经过编译器编译或解释,才能转化成机器能够识别并能执行的二进制代码 B.如何一步步的跟踪代码,找到问题,搞明白为何程序不能正常运行,这个过程称为调试程序 C.自动化的工具同样也能够帮助你跟踪程序,尤其当程序很复杂时效果更加明显,这种工具叫做调试器 D.调试器不能解决程序中出现的问题 参考答案:D 17. 议程的近似方法有( ) A.迭代法 B.牛顿法 C.弦截法 D.二分法 参考答案:ABCD 18. 对一组数据(84,47,25,15,21)排序,数据的排列次序在排序的过程中的变化为(1) 84 47 25 15 21 (2) 15 47 25 84 21 (3) 15 21 25 84 47 (4) 15 21 25 47 84 则采用的排序方法是( )。 A.选择 B.冒泡 C.快速 D.插入 参考答案:A 22春"计算机科学与技术"专业《计算方法》在线
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值