C语言中数组排序浅析

目录
  • 前言
  • 一、插入排序
    • 1、思路
    • 2、具体步骤
    • 3、代码实现
    • 4、复杂度
  • 二、冒泡排序
    • 1、思路
    • 2、具体步骤
    • 3、代码实现
    • 4、复杂度
  • 三、选择排序
    • 1、思路
    • 2、具体步骤
    • 3、代码实现
    • 4、复杂度
  • 四、希尔排序
    • 1、思路
    • 2、具体步骤
    • 3、代码实现
    • 4、复杂度
  • 例题及其解答
    • 题目描述
    • 输入描述
    • 输出描述
    • 示例1
    • 示例2
    • 解答
    • 结语

前言

本文介绍了几种c语言中对乱序数组的排序方式。

具体的内容有:

  • 插入排序;
  • 冒泡排序;
  • 选择排序;
  • 希尔排序;

具体内容详见下文。

一、插入排序

1、思路

首先假设数组的的前n位元素是有序的,然后从第n+1位开始,将此元素插入到前面,使得前n+1位元素有序,以此类推,直至整个数组有序。

在对第n+1位元素操作时,使用临时变量存放该元素的值,从第n位元素开始向前比较,同时将与其比较的元素向后移动,直到与其比较的元素比其小时,将临时变量中的值放入该元素后的一个数组元素中。

2、具体步骤

1.从第一个元素开始,该元素可以认为已经被排序。

2.取下一个元素存入临时变量temp,对前方有序序列从后往前扫描。

3.如果该元素大于temp,则将该元素移到下一位。

4.重复步骤3,直到找到已于等于temp的元素。

5.temp插入到该元素的后面一位,如果所有有序元素都大于temp,则将temp插入到下标为0的位置(既数组的首位,说明该元素是目前最小的元素)。

6.重复以上的2~5步骤,直至操作完整个数组中的所有元素。

3、代码实现

void insertsort(int arr[], int len)
{
	int j;
	for(j=0; j<len-1; j++)
	{
		int end=j;    //前end位为有序部分
		int temp=arr[j+1];    //临时变量存放
		while(end>=0)
		{
			if(arr[end]>temp)    //将temp变量与前面一位元素比较
			{
				arr[end+1]=arr[end];    //将比temp变量大的元素向后移动一位
				end--;    //继续向前比较
			}
			else    //找到比temp变量小的元素
			{
				break;
			}
		}
		arr[end+1]=temp;    //将temp变量插入有序部分
	}
}

4、复杂度

时间复杂度: O(N)~O(N^2)

空间复杂度:O(1)

二、冒泡排序

1、思路

通过对数组内相邻元素的比较,使较大的元素向后移动,较小的元素向前移动,不断循环此过程,直至整个数组有序。

当第n次循环结束后,数组的最后n位为有序,所以每循环一次,就可以将循环的范围(后界)向前减少一位元素。

2、具体步骤

1.将数组中的第一个元素与下一个元素进行比较,若第一个元素较大,则交换位置。

2.继续比较下两个元素的大小,将较大的元素放在靠后的位置。

3.重复步骤2,直至完成第n-1个元素与第n个元素的比较。

4.将循环的后界减一,重复1~5步骤。

5.当循环的范围减为1时,此时的为有序数组。

3、代码实现

void bubblesort(int arr[], int len)
{
	int j,k;    //定义循环因子,嵌套双层循环
	for(j=0; j<len-1; j++)    //设置循环后界
	{
		for(k=0; k<len-j-1; k++)    //不断向后进行比较
		{
			if(arr[k]>arr[k+1])    //比较相邻的元素
			{
				int temp=arr[k];    //三杯水交换法
				arr[k]=arr[k+1];
				arr[k+1]=temp;
			}
		}
	}
}

4、复杂度

时间复杂度: O(N)~O(N^2)

空间复杂度: O(1)

三、选择排序

1、思路

不断扫描数组,每次选出一个最小值和一个最大值,分别放在序列的首位置和末位置,然后将序列的首位置与末位置分别向后与前移动一位。直至排完整个数组。

2、具体步骤

1.定义序列的首末位置。

2.扫描首末位置之间的序列,选出一个最小值min和一个最大值max,记录下标值。

3.将最小值放入首位置start,最大值放入末位置end。

4.将首位置向后移动一位,末位置向前移动一位。

5.重复2~4步骤,直至首末位置重合(start>=end),此时的数组为有序数组。

3、代码实现

void selectsort(int arr[], int len)
{
	int start=0, end=len-1;    //定义首末位置
	while(start<end)
	{
		int max=start;
		int min=start;
		int j;
		for(j=start; j<=end; j++)    //扫描首末位置之间的序列
		{
			if (arr[j] < arr[min])    //选取最小值
			{
				min = j;    //记录最小值的下标
			}
			if (arr[j] > arr[max])    //选取最大值
			{
				max = j;    //记录最大值的下标
			}
		}
		int temp=arr[min];    //三杯水交换,将最小值放入首位置
		arr[min]=arr[start];
		arr[start]=temp;
		if (start == max)    //防止最大值在首位置被换走
		{
			max = min;
		}
		temp=arr[max];    //三杯水交换,将最大值放入末位置
		arr[max]=arr[end];
		arr[end]=temp;
		start++;    //首位置后移一位
		end--;    //末位置前移一位
	}
}

4、复杂度

时间复杂度: O(N^2)

空间复杂度: O(1)

四、希尔排序

1、思路

定义一个小于数组长度增量,将整个数组中每隔一个增量的元素分为一组,对每组中的元素进行插入排序,再将增量减小,之后重复以上过程,直至增量减小为1时,对已经进行过预处理的数组进行插入排序,达到减小复杂度的目的。

2、具体步骤

1.定义一个小于数组长度的增量gap(通常为数组长度的一半),将数组进行分组。

2.对每组中的元素进行插入排序的操作,使之有序。

3.减小增量gap(通常为减为一半),将数组再度细分。

4.重复2~3步骤,直至增量gap减小为1。

5.此时对整个数组再做插入排序操作,使整个数组有序。

3、代码实现

void shellsort(int arr[], int len)
{
	int gap=len;    //定义增量
	while(gap>1)
	{
		gap=gap/2;    //将增量减小
		int j;
		for(j=0; j<len-gap; j++)    //将数组分组
		{
			int end=j;
			int temp=arr[end+gap];    //对每组元素进行插入排序
			while(end>=0)
			{
				if(arr[end]>temp)
				{
					arr[gap+end]=arr[end];
					end-=gap;
				}
				else
				{
					break;
				}
			}
			arr[end+gap]=temp;
		}
	}
}

4、复杂度

时间复杂度: 平均 O(N^1.3)

空间复杂度: O(1)

具体使用

#include<stdio.h>
void insertsort(int arr[], int len)    //选择排序
{
	int j;
	for(j=0; j<len-1; j++)
	{
		int end=j;
		int temp=arr[j+1];
		while(end>=0)
		{
			if(arr[end]>temp)
			{
				arr[end+1]=arr[end];
				end--;
			}
			else
			{
				break;
			}
		}
		arr[end+1]=temp;
	}
}
void bubblesort(int arr[], int len)    //冒泡排序
{
	int j,k;
	for(j=0; j<len-1; j++)
	{
		for(k=0; k<len-j-1; k++)
		{
			if(arr[k]>arr[k+1])
			{
				int temp=arr[k];
				arr[k]=arr[k+1];
				arr[k+1]=temp;
			}
		}
	}
}
void shellsort(int arr[], int len)    //希尔排序
{
	int gap=len;
	while(gap>1)
	{
		gap=gap/2;
		int j;
		for(j=0; j<len-gap; j++)
		{
			int end=j;
			int temp=arr[end+gap];
			while(end>=0)
			{
				if(arr[end]>temp)
				{
					arr[gap+end]=arr[end];
					end-=gap;
				}
				else
				{
					break;
				}
			}
			arr[end+gap]=temp;
		}
	}
}
void selectsort(int arr[], int len)    //选择排序
{
	int start=0, end=len-1;
	while(start<end)
	{
		int max=start;
		int min=start;
		int j;
		for(j=start; j<=end; j++)
		{
			if (arr[j] < arr[min])
			{
				min = j;
			}
			if (arr[j] > arr[max])
			{
				max = j;
			}
		}
		int temp=arr[min];
		arr[min]=arr[start];
		arr[start]=temp;
		if (start == max)
		{
			max = min;
		}
		temp=arr[max];
		arr[max]=arr[end];
		arr[end]=temp;
		start++;
		end--;
	}
}
int main()
{
	int arr[10]={9,8,7,6,5,4,3,2,1,0};    //乱序数组
	int len=sizeof(arr)/4;
	int i;
	for(i=0; i<len; i++)
	{
		printf("%d\t", arr[i]);    //输出初始数组,用于比较
	}
	putchar('\n');
	selectsort(arr, len);    //调用函数对数组进行排序,这里选用的是选择排序的方式
	for(i=0; i<len; i++)
	{
		printf("%d\t", arr[i]);    //输出排完序后的数组
	}
	putchar('\n');
	return 0;
 } 

例题及其解答

题目描述

来源:牛客网

小明平时学习太用功了,闲暇时间就喜欢玩一种数字游戏,在这个游戏中,他每次会使用n个正整数先构造一个数列(x1,……,xn),并可以根据需要无限次执行以下操作:

选择两个不同的i,j,其中xi>xj,然后将xi改为xi-xj。

请你帮小明算一下,通过这样的一系列操作,求出最终处理过数列的总和最小值是多少?

输入描述

第一行一个整数n代表数列的长度,2<=n<=100,

第二行包含n个正整数x1 x2 x3 ... xi, 1<=xi<=100.

输出描述

经过多次操作后,数列总和的最小值(整数)。

示例1

输入

5
45 12 27 30 18

输出

15

示例2

输入

3 2 4 6

3
2 4 6

输出

6

说明

在输出样例2中进行了以下操作:x3 = x3 - x2, x2 = x2 - x1,经过这两步操作后,所有的数字都相等,因此操作不能再进行下去了,每个数都是2,因此6就是总和的最小值。

解答

#include<stdio.h>
void sort(int arr[], int n)    //本题我使用的是冒泡排序,也可使用其他排序方式
{
    int i,j;
    for(i=0; i<n-1; i++)
    {
        for(j=0; j<n-1-i; j++)
        {
            if(arr[j]<arr[j+1])
            {
                int temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }
        }
    }
}
int main()
{
    int n;
    scanf("%d",&n);    //输入数列长度
    int arr[n];    //定义相应长度的数组
    int i;
    for(i=0; i<n; i++)
    {
        scanf("%d", &arr[i]);    //将输入的数据存入数组
    }
    while(1)
    {
        sort(arr,n);    //对数组进行排序
        if(arr[0]==arr[n-1])    //判断数组的首末元素是否相等
        {
            break;    //若相等,则无法再进行作差操作
        }
        for(i=0;i<n-1; i++)    //对数组中的相邻且不相等的元素作差
        {
            if(arr[i]>arr[i+1])
            {
                arr[i]=arr[i]-arr[i+1];
            }
        }
    }
    int sum=0;
    for(i=0; i<n; i++)    //对最终的数组进行求和
    {
        sum=sum+arr[i];
    }
    printf("%d\n", sum);    //输出答案
    return 0;
}

结语

以上就是四种数组排序方式的全部内容,以及在例题中的应用。

到此这篇关于C语言中数组排序浅析的文章就介绍到这了,更多相关C语言数组排序内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言中使用qsort函数对自定义结构体数组进行排序

    目录 使用qsort函数对自定义结构体数组进行排序 结构体 排序函数 总体代码 C语言 qsort()函数详解 1.qsort概念介绍 2.qsort()函数实现(循序渐进式讲解) 3.小结 使用qsort函数对自定义结构体数组进行排序 qsort进行排序的数组存储的不能是结构体的指针,需要是结构体本身. 结构体 struct student{     char* id;     int mark; }arr[4], test0={"0001",80}, test1={"00

  • C语言对数组元素进行冒泡排序的实现

    在实际开发中,有很多场景需要我们将数组元素按照从大到小(或者从小到大)的顺序排列,这样在查阅数据时会更加直观,例如: 一个保存了班级学号的数组,排序后更容易分区好学生和坏学生: 一个保存了商品单价的数组,排序后更容易看出它们的性价比. 对数组元素进行排序的方法有很多种,比如冒泡排序.归并排序.选择排序.插入排序.快速排序等,其中最经典最需要掌握的是「冒泡排序」. 以从小到大排序为例,冒泡排序的整体思想是这样的: 从数组头部开始,不断比较相邻的两个元素的大小,让较大的元素逐渐往后移动(交换两个元素

  • c语言合并两个已排序数组的示例(c语言数组排序)

    问题:将两个已排序数组合并成一个排序数组 这里先不考虑大数据量的情况(在数据量很大时不知大家有什么好的思路或方法?),只做简单数组的处理. 简单代码如下: 说明:之所以把merge函数定义成返回数组长度,是因为后续会有重复数据合并功能的merge版本,考虑到接口一致性. 复制代码 代码如下: #include <stdio.h>#include <stdlib.h>#include <string.h> int merge(int* ar1, int len1, int

  • C语言将数组中元素的数排序输出的相关问题解决

    问题描述:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个.例如输入数组{32,  321},则输出这两个能排成的最小数字32132.请给出解决问题的算法,并证明该算法.       思路:先将整数数组转为字符串数组,然后字符串数组进行排序,最后依次输出字符串数组即可.这里注意的是字符串的比较函数需要重新定义,不是比较a和b,而是比较ab与 ba.如果ab < ba,则a < b:如果ab > ba,则a > b:如果ab = ba,则a = b.比较

  • C语言算法练习之数组元素排序

    目录 一.问题描述 二.算法实例编译环境 三.算法实例实现过程 3.1.包含头文件 3.2.定义宏和声明数组 3.3.声明相关变量 3.4.随机生成十个数字赋值给数组 3.5.输出随机生成的十个数字 3.6.数组从小到大进行排序 3.7.输出数组元素排序好的数字 四.经典算法实例程序 完整代码 4.1.main.h文件 4.2.main.c文件 五.总结 一.问题描述 求数组的排序 问题的描述 如下几点所示 使用rand()库函数随机生成10个1-100之间的数字. 声明数组的大小为10. 随机

  • C语言中数组排序浅析

    目录 前言 一.插入排序 1.思路 2.具体步骤 3.代码实现 4.复杂度 二.冒泡排序 1.思路 2.具体步骤 3.代码实现 4.复杂度 三.选择排序 1.思路 2.具体步骤 3.代码实现 4.复杂度 四.希尔排序 1.思路 2.具体步骤 3.代码实现 4.复杂度 例题及其解答 题目描述 输入描述 输出描述 示例1 示例2 解答 结语 前言 本文介绍了几种c语言中对乱序数组的排序方式. 具体的内容有: 插入排序: 冒泡排序: 选择排序: 希尔排序: 具体内容详见下文. 一.插入排序 1.思路

  • R语言中时间序列分析浅析

    时间序列是将统一统计值按照时间发生的先后顺序来进行排列,时间序列分析的主要目的是根据已有数据对未来进行预测. 一个稳定的时间序列中常常包含两个部分,那么就是:有规律的时间序列+噪声.所以,在以下的方法中,主要的目的就是去过滤噪声值,让我们的时间序列更加的有分析意义. 语法 时间序列分析中ts()函数的基本语法是 timeseries.object.name <- ts(data, start, end, frequency) 以下是所使用的参数的描述 data是包含在时间序列中使用的值的向量或矩

  • 浅析Go语言中闭包的使用

    目录 闭包基本介绍 闭包实现数字累加 代码说明 代码分析 闭包案例 上代码 代码说明 闭包基本介绍 闭包就是 一个函数 和其相关的 引用环境 组合的一个整体 好处: 保存引用的变量,下次继续使用,不会销毁 下面通过闭包的方式,写一个数字累加器,体验一下闭包的妙处 闭包实现数字累加 package main import "fmt" // 累加器 // 闭包 - 函数柯里化 // 返回值类型: func(int) int func AddUpper() func(int) int { v

  • 浅析Go语言中数组的这些细节

    目录 Go语言基础二 len&cap 二维数组的遍历 数组的拷贝与传参 求数组所有元素之和 例题:数组元素匹配问题 今日总结 Go语言基础二 len&cap 书接上文,我们提到二维数组中的第二个维度的数组不能用...来表示,接下来我们要认识两个新的函数,它们分别是len和cap package main ​ func main() { a := [2]int{} println(len(a), cap(a)) } 由上方代码可知,我们在main函数里面定义了一个a数组,长度为2,未进行初始

  • 深入浅析C语言中堆栈和队列

    1.堆和栈 (1)数据结构的堆和栈 堆栈是两种数据结构. 栈(栈像装数据的桶或箱子):是一种具有后进先出性质的数据结构,也就是说后存放的先取,先存放的后取.这就如同要取出放在箱子里面底下的东西(放入的比较早的物体),首先要移开压在它上面的物体(放入的比较晚的物体). 堆(堆像一棵倒过来的树):是一种经过排序的树形数据结构,每个结点都有一个值.通常所说的堆的数据结构,是指二叉堆.堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆.由于堆的这个特性,常用来实现优先队列,堆的存取是随意,

  • 浅析C语言中的数组及字符数组

    我们来编写一个程序,以统计各个数字.空白符(包括空格符.制表符及换行符)以及所有其它字符出现的次数.这个程序的实用意义并不大,但我们可以通过该程序讨论 C 语言多方面的问题. 所有的输入字符可以分成 12 类,因此可以用一个数组存放各个数字出现的次数,这样比使用 10 个独立的变量更方便.下面是该程序的一种版本: #include <stdio.h> /* count digits, white space, others */ main() { int c, i, nwhite, nothe

  • C语言中数组的使用详解

    目录 1 数组的基本概念 2 数组定义语法 3 一维数组的初始化 3.1 全部初始化 3.2 部分元素赋初值 3.3 省略长度赋初值 4 一维数组的使用示例 4.1 求最大值.最小值.平均值 4.2 数组逆置 4.3 数组排序 4.3.1 冒泡排序 4.3.2 选择排序 选择列表中的最小值与未排序列表中的第一个值互换位置. 4.3.3 直接插入排序 5 二维数组 5.1 二维数组的概念 5.2 二维数组的初始化 5.2.1 全部初始化 按行全部赋初值 5.2.2 部分初始化 5.2.3 省略长度

  • Go语言中的延迟函数defer示例详解

    前言 大家都知道go语言的defer功能很强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.Go 语言中延迟函数 defer 充当着 try...catch 的重任,使用起来也非常简便,然而在实际应用中,很多 gopher 并没有真正搞明白 defer.return.返回值.panic 之间的执行顺序,从而掉进坑中,今天我们就来揭开它的神秘面纱!话不多说了,来一起看看详细的介绍吧. 先来运行下面两段代码: A. 匿名返回值的情况 package main import ( "fmt&qu

  • Go语言中的流程控制结构和函数详解

    这小节我们要介绍Go里面的流程控制以及函数操作. 流程控制 流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑.Go中流程控制分三大类:条件判断,循环控制和无条件跳转. if if也许是各种编程语言中最常见的了,它的语法概括起来就是:如果满足条件就做某事,否则做另一件事. Go里面if条件判断语句中不需要括号,如下代码所示: 复制代码 代码如下: if x > 10 {     fmt.Println("x is greater than 10&

  • Go语言中的指针运算实例分析

    本文实例分析了Go语言中的指针运算方法.分享给大家供大家参考.具体分析如下: Go语言的语法上是不支持指针运算的,所有指针都在可控的一个范围内使用,没有C语言的*void然后随意转换指针类型这样的东西.最近在思考Go如何操作共享内存,共享内存就需要把指针转成不同类型或者对指针进行运算再获取数据. 这里对Go语言内置的unsafe模块做了一个实验,发现通过unsafe模块,Go语言一样可以做指针运算,只是比C的方式繁琐一些,但是理解上是一样的. 下面是实验代码: 复制代码 代码如下: packag

随机推荐