2.冒泡排序、选择排序、插入排序

冒泡排序

从数组最左端开始向右遍历,依次比较相邻元素大小,如果“左元素>右元素”就交换它俩。遍历完成后,最大的元素会被移动到数组的最右端。

算法优化: 如果某轮“冒泡”中没有执行任何交换操作,说明数组已经完成排序,可直接返回结果。因此,可以增加一个标志位 fiag 来监测这种情况,一旦出现就立即返回。
经过优化,冒泡排序的最差和平均时间复杂度仍为O(n2)
但当输入数组完全有序时,可达到最佳时间复杂度 O(n)。

void BubbleSort(int *arr,int n){
	while(n){
		int flag = 0;//监测优化
		for(int i=1;i<=n;i++){
			if(arr[i-1]>arr[i]){//左>右交换 
				int temp = arr[i];
				arr[i] = arr[i-1];
				arr[i-1] = temp; 
				flag = 1;//执行过操作 
			}
		}
		if(flag==0) break; 
	}
} 

具体逻辑如下:

  1. 在每一轮遍历中,通过嵌套的 for 循环,比较相邻的两个元素的大小。
  2. 如果发现左边的元素大于右边的元素,则进行交换,以确保较小的元素在前,较大的元素在后。
  3. 同时,设置一个标志位 flag 为 0,用于标记这一轮是否有进行交换操作。如果没有进行交换操作,说明数组已经是有序的,可以提前结束排序过程。
  4. 如果进行了交换操作,则将 flag 置为 1,表示进行了交换。
  5. 每一轮遍历结束后,检查 flag 是否为 0,如果为 0,则说明已经完成排序,直接跳出循环。
  6. 每次遍历都会将数组中最大(或最小)的元素沉到最后(或最前),因此每轮遍历都可以缩小遍历范围,即将数组的长度减一(n--)。
  7. 最终完成所有遍历后,数组就会按照从小到大的顺序排列。

需要注意的是,这段代码中数组下标从 1 开始,而不是通常的从 0 开始,因此在比较和交换的时候需要将下标减 1。此外,在每一轮遍历中,都需要将 flag 重新置为 0,以便进行下一轮的判断。

选择排序

每次从待排序列中选出一个最小值,然后放在序列的起始位置,直到全部待排数据排完即可。
实际上,我们可以一趟选出两个值,一个最大值一个最小值,然后将其放在序列开头和末尾,这样可以使选择排序的效率快一倍。

时间复杂度:

最坏情况:O(N^2)

最好情况:O(N^2)
空间复杂度:O(1)

void selectionSort(int arr[], int n) {
    int left = 0, right = n - 1;
    while (left < right) {
        int minIndex = left, maxIndex = right;
        // 找出当前范围内的最小值和最大值的下标
        for (int i = left; i <= right; i++) {
            if (arr[i] < arr[minIndex]) {
                minIndex = i;
            } else if (arr[i] > arr[maxIndex]) {
                maxIndex = i;
            }
        }
        
        // 将最小值放在序列开头,将最大值放在序列末尾
        swap(&arr[left], &arr[minIndex]);
        swap(&arr[right], &arr[maxIndex]);
        
        // 缩小范围
        left++;
        right--;
    }
}

 插入排序

最优时间复杂度是O(n),平均和最坏时间复杂度都是O($n^2$)

实际上是O($n^2$/4),比选择排序期望值的一半

void InsertSort(int *arr,int n){
	for(int i=0;i<n-1;i++){
		int j = i;//有序序列最后一个元素的下标
		int temp = arr[j+1];//待插入元素 
		while(j>=0){
			//已排序区元素比插入的数大就向后移 
			if(arr[j]>temp){
				arr[j+1] = arr[j]
				j--; 
			}else{//比插入的数小跳出循环
				break;
			} 			
		} 
		arr[j+1]=temp;
	}
}

 代码逻辑如下:

  1. 外层循环:这段代码使用一个 for 循环来遍历数组中除最后一个元素外的所有元素。由于插入排序的特性是将每个元素逐个插入到已排序部分的正确位置,所以循环次数是 n-1,其中 n 是数组的长度。

  2. 内层循环:在每次外层循环迭代时,会定义一个变量 j 并将其初始化为当前已排序部分的最后一个元素的下标 i。该变量 j 用于确定待插入元素的插入位置。

  3. 待插入元素的保存:在外层循环中,每次都会将下一个待插入的元素保存到变量 temp 中,即 temp = arr[j+1]

  4. 插入操作:内层循环是一个 while 循环,其条件是 j 大于等于 0。在循环过程中,会不断将已排序部分中比待插入元素大的元素向后移动一个位置,为待插入元素腾出位置。

  5. 循环终止条件:内层循环中,当发现已排序部分的元素不再比待插入元素大时,即找到了待插入元素的插入位置,跳出循环。

  6. 插入操作的执行:在内层循环之外,将待插入元素 temp 放置在找到的插入位置的后面,即 arr[j+1] = temp。这一步操作完成了待插入元素的插入。

  7. 循环进行:外层循环继续迭代,重复上述操作,直到所有元素都被正确地插入到已排序部分为止。

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值