算法学习(1)—排序

一些常用排序算法

1、插入排序

  • 概念
    插入排序算法是一个对少量元素进行排序的有效算法,是一种稳定排序算法(不会交换值相同的元素)。
    最好时间复杂度为O(n),最坏时间复杂度为O(n2),平均时间复杂度为O(n2),空间复杂度为O(1)。

  • 理解
    从一本书上看到描述这个算法的一段话,我觉得很贴切,很好理解:
    插入排序类似于打牌。摸牌时,刚开始手上没有牌,摸出第一张,随意放在左手上, 以后每一次摸牌,都会按照花色从小到大地将牌插入到合适的位置, 直到所有牌摸完。
    例:
    // { (4) , 8 , 3 , 9 , 0 , 2 , 7 }
    // { (4 , 8) , 3 , 9 , 0 , 2 , 7 }
    // { (3 , 4 , 8) , 9 , 0 , 2 , 7 }
    // { (3 , 4 , 8 , 9) , 0 , 2 , 7 }
    // { (0 , 3 , 4 , 8 , 9) , 2 , 7 }
    // { (0 , 2 , 3 , 4 , 8 , 9) , 7 }
    // { (0 , 2 , 3 , 4 , 7 , 8 , 9) }

  • 代码

void InsertSort(int *num,int n){
	int i;
	for(i=1;i<n;i++){ 	//遍历数组中的元素 
		int j=i-1;	//当前元素的前一个元素,即 num[i-1] 
		int t=num[i];	//保存 num[i] 
		while( j >= 0 && t < num[j]){	//逐个向前比较 
			num[j+1]=num[j];	//将已比较的元素往后移 
			j--;
		}
		num[j+1]=t;	//插入相应位置 
	}
}
  • 上述代码注意点
  1. 没有设置“哨兵”,即用数组num的第一个元素 num[0] 来存储待排序元素。
  2. 从小到大排序
  3. 用于整型数据

2、冒泡排序

  • 概念
    冒泡排序算法是一种交换排序算法,是一种稳定排序算法。
    最好时间复杂度为O(n),最坏时间复杂度为O(n2),平均时间复杂度为O(n2),空间复杂度为O(1)。

  • 理解
    根据我的理解,冒泡排序的核心为 比较+交换。元素之间两两比较,大的一方往后移。这个过程就像水中的气泡一样,重气泡往下沉,轻气泡往上浮。
    例:
    数组第一次遍历,比较了 n-1 次并根据需要进行了元素交换,这样值最大的元素就“冒”到了数组的最后;
    第二次遍历时,只需比较 n-2 次,这样值第二大的元素就“冒”到了数组的倒数第二个位值;
    ……
    以此类推,当只进行了比较,而无发生交换时,则排序终止。

  • 代码

void bubbleSort(int *num,int n){
	int flag;	//交换标志 
	int i,t,j;
	for(i=0;i<n-1;i++){	//进行遍历 
		flag=0;	//重置交换标志 
		j=0;
		while(j<n-i-1){  //两两进行比较 
			if(num[j]>num[j+1]){
				flag=1;		//发生交换,将标志设为 1 
				t=num[j+1];
				num[j+1]=num[j];
				num[j]=t;
			}
			++j;
		}
		if(flag==0) break;	//若无发生交换则排序已完毕 
	}
} 
  • 上述代码注意点
  1. 从小到大排序
  2. 用于整型数据

3、快速排序

  • 概念
    在快速排序中,元素的比较和移动是从两端向中间进行的。
    快速排序是一个递归的过程,是一种不稳定的算法。
    最好时间复杂度为O(nlog2n),最坏时间复杂度为O(n2),平均时间复杂度为O(nlog2n)。

  • 理解

  • 快速排序的基本思想是:
    ①选一个轴值(即比较的基准),将待排序元素划分为独立的两部分。
    ②左侧元素均<=轴值,右侧元素均>=轴值
    ③分别对这两部分重复上述过程,直到整个序列有序。

  • 一次划分的基本步骤:
    ①选轴值。轴值的选取可从序列两端选取,也可从中间选取。(这里选左端
    ② i -> 左,j -> 右
    ③ a [ j ] 与轴值(即 a [ i ] )比较,若 a [ j ] <轴值,a [ j ] 与轴值交换位置,循环结束。此时轴值即为a [ j ] ; 否则 j = j - 1,循环继续;
    ④a [ i ] 与轴值(即 a [ j ] )比较,若 a [ i ] >轴值,a [ i ] 与轴值交换位置,循环结束。此时轴值即为a [ i ] ; 否则 i = i + 1,循环继续;
    ⑤当 i = j 时,一次划分结束。

  • 代码

快速排序一次划分:

int Partition(int *a,int first,int last){
	int i=first,j=last;
	while(i<j){	// i,j不是指向同一个值时 
		
		for(i;i<j;i++)	//从左边开始扫描,以 a[j] 为轴值 
			if(a[i]>a[j]){	//若左边的值比右边的值大,则两个值进行交换 
				int t=a[i];
				a[i]=a[j];
				a[j]=t;
				break;	//左边扫描结束 
			}
		
		for(j;j>i;j--){	//从右边开始扫描,以 a[i] 为轴值 
			if(a[j]<a[i]){	//若右边的值比左边的值小,则两个值进行交换
				int t=a[j];
				a[j]=a[i];
				a[i]=t;
				break;	//右边扫描结束 
			}
		}
	}
	
	if(i==j) return i;	//返回最后的位置 
} 

快速排序:

void QuickSort(int *a,int first,int last){
	int i=first,j=last;
	if(i<j){	//区间长度大于一,进行一次划分,否则递归结束 
		int t=Partition(a,i,j);	//一次划分 
		QuickSort(a,i,t-1);	//递归地对左侧子序列进行快速排序 
		QuickSort(a,t+1,j);	//递归地对右侧子序列进行快速排序 
	}
} 
  • 上述代码注意点
  1. 从小到大排序
  2. 用于整型数据

4、选择排序

  • 概念
    选择排序是最基本及简单的排序算法之一,它重复地从待排序的元素里选出最大或最小的元素进行排序。
    选择排序是一种不稳定的算法。
    最好、最坏和平均时间复杂度都为O(n2)。

  • 理解
    (1)将整个序列划分为有序区和无序区,初始时有序区为空,无序区含有待排序的所有元素。
    (2)在无序区中选取值最小的元素,与无序区的第一个元素交换,使得有序区扩展了一个元素,同时无序区减少了一个元素。
    (3)重复(2)步骤,直到无序区只剩下一个元素。此时所有元素已按从小到大的顺序排列。

  • 过程示例:
    初始序列 :[ 49 27 65 97 76 13 38 ]
    第一趟 : 13 [ 27 65 97 76 49 38 ]
    第二趟 : 13 27 [ 65 97 76 49 38 ]
    第三趟 : 13 27 38 [ 97 76 49 65 ]
    第四趟 : 13 27 38 49 [ 76 97 65 ]
    第五趟 : 13 27 38 49 65 [ 97 76 ]
    第六趟 : 13 27 38 49 65 76 97

  • 代码

void selectSort(int *a,int n){
	int index=0,i,j;
	for(i=0;i<n;i++){ //对 n 个单元进行 n 趟简单选择排序 
		index=i; //记录最小值的下标 
		for(j=i+1;j<n;j++){	//在无序区中选取最小值 
			if(a[j]<a[index]) index=j; 
		}
		if(index!=i){	//当无序区的最小值不是无序区的第一个元素时,两元素交换 
			int t=a[i];
			a[i]=a[index];
			a[index]=t;
		}
	}
}
  • 上述代码注意点
  1. 从小到大排序
  2. 用于整型数据
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值