算法篇 -- 排序

冒泡排序

算法思想

冒泡排序是一种简单直观的排序算法,需要重复多次遍历待排元素。在每次的遍历过程中,依次比较两个元素的大小,如果顺序错误就进行交换,每次遍历结束之后,会有一个较大或较小的元素逐渐“浮”到数列的顶端。

算法评价

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

代码实现(C语言,数组)

//参数:数组 数组长度
void bubbleSort(int nums[], int n){
	for(int i = n-1; i >= 0; i--){
		for(int j = 0; j < i; j++){//j<i,每遍历一次,后面有序的数据个数+1,后面的数据无需再做比较
			//顺序有误,进行交换
            if(nums[j+1] < nums[j]){
				int temp = nums[j];
				nums[j] = nums[j+1];
				nums[j+1] = temp;
			}
		}
        //输出每次遍历冒泡的结果
		for(int j = 0; j < n; j++){
			printf("%d ", nums[j]);
		}
		printf("\n");
	}
}

优化:

1. j<i,随着遍历,后面的数据有序,则无需进行比较

2. 在一次遍历过程中,若发现没有元素进行交换,则表示已经有序,冒泡排序结束。

选择排序

每次选择待排元素中的最大(小)值,放到待排序列的第一个位置,依次处理,直到所有元素排序结束

算法评价

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

空间复杂度:O(1)

适合于待排元素较少的情况

代码实现(C语言,数组)

//参数:数组 数组长度
void selectionSort(int nums[], int n){
	for(int i = 0; i < n; i++){
		int minPos = i;//记录最小值的位置
		//遍历数组,找到待排元素中最小值 
		for(int j = i+1; j < n; j++){
			if(nums[j] < nums[minPos]){
				minPos = j;
			}
		}
		//将该最小值和i位置的数值进行交换
		int temp = nums[minPos];
		nums[minPos] = nums[i];
		nums[i] = temp;
		//输出此轮排序结果
		for(int j = 0; j < n; j++){
			printf("%d ", nums[j]);
		} 
		printf("\n");
	} 
}

插入排序

算法思想

将第一个元素视作有序序列,后面的元素视作待排序列,对每一个待排序列中的元素,查找在有序序列中位置,并放入,使其仍为有序序列,直到所有待排元素都插入完毕。(在有序序列中查找元素的合适位置时,元素依次后移,直到找到合适位置,放入当前待排元素)。

代码实现(C语言,数组)

//插入排序 参数:数组 数组长度 
void insertionSort(int nums[], int n){
	int temp;//暂存当前待排元素
	int j;
	for(int i = 1; i < n; i++){
		//每个元素依次往前找到最适合的位置 
		temp = nums[i];
		for(j = i-1; j >= 0 && nums[j] > temp ; j--){
			nums[j+1] = nums[j];
		}
		nums[j+1] = temp;
		//输出此轮排序的结果
		for(int k = 0; k < n; k++){
			printf("%d ", nums[k]);
		} 
		printf("\n");
	} 
}

希尔排序

算法思想

也称递减增量排序算法,是插入排序的一种更加高效的改进版本。但希尔排序是非稳定排序算法。

希尔排序的基本思想是:先将整个待排序列分割为若干子序列,并分别进行直接插入排序,待整个序列“基本有序”时,再对整个序列进行直接插入排序。

选择一个增量序列,按增量序列对待排序列进行排序,每次排序结束后,增量进行改变,到最后增量为1时,整个序列作为一个整体进行排序。

代码实现(C语言,数组)

//希尔排序 参数:数组 数组长度
void shellSort(int nums[], int n){
	int gap = n / 2;//设置增量
	int temp;
	while(gap > 0){
		//进行插入排序
		for(int i = gap; i < n; i += gap){
			temp = nums[i];
			int j = i-gap;
			for(; j >= 0 && nums[j] > temp; j = j-gap){
				nums[j+gap] = nums[j];
			}
			nums[j+gap] = temp;
		}
		//更新gap 
		gap = gap / 2;
	}
}

归并排序

算法思想

归并排序是建立在归并上的一种有效的排序算法。该算法是分治法的典型应用。

归并排序的实现分为两部分:自上而下的递归,自下而上的迭代。

对待排序列进行递归分组,从中间分为两部分,再依次分下去,直到元素为一个。将每个单个元素看作一个已经有序的序列,两两合并,合并时,取较小的在前,合并为一个有序序列,依次递归返回,最后将左边部分和右边部分的有序序列进行合并,合并为一整个有序序列。

代码实现(C语言,数组)

//归并排序 参数:数组,左边界,右边界
void mergeSort(int nums[], int left, int right){
	if(left >= right){
		return true;
	}
	int mid = (left + right)/2;
	//对左边进行排序归并 
	mergeSort(nums, left, mid);
	//对右边进行排序归并 
	mergeSort(nums, mid+1, right);
	//对left 到 right 进行归并排序 
	merge(nums, left, mid, right);
	return true;
} 

//两个数组分别进行排序,之后合并  参数:数组 左边界 中间位置 右边界
void merge(int nums[], int left, int mid, int right){
	//待排序和归并的数组的大小 
	int m = right - left + 1;
	//申请一个临时数组,复制保存原数组 
	int tempNum[m];
	for(int i = 0, j = left; i < m; i++, j++){
		tempNum[i] = nums[j];
	} 

	//从tempNum中,依次拿出left--mid和mid+1--right中较小的数,
	//放入原数组中(覆盖原数组),以达到归并的目的
	int first = 0;
	int middle = (m-1)/2;
	int second = middle +1;
	int real = left;
	//进行数组合并
	while(first <= middle && second < m){
		if(tempNum[first] < tempNum[second]){
			nums[real] = tempNum[first];
			real++;
			first++;
		}else{
			nums[real] = tempNum[second];
			real++;
			second++;
		}
	} 
	//将剩余部分进行合并
	if(first <= middle){
		//第一个数组未合并完
		second = first;
	} 
	while(real <= right){
		nums[real] = tempNum[second];
		real++;
		second++;
	}
}

快速排序

算法思想

快速排序采用分治的策略,将一个数组通过选择"基准",将其分为两个子数组。先从数组中选出一个数作为基准,在第一次划分的过程中,将大于基准的放在基准的右侧(或左侧),小于基准的放在基准的左侧(或右侧),此次划分结束后,"基准"元素的位置即为整个数组有序时它的所在位置。再以递归的思想,分别对"基准"左侧部分、右侧部分进行相同的操作。最终即可实现元素排序。

算法评价

最坏情况时间复杂度:O(n^2)

平均时间复杂度:O(nlogn)

代码实现(C语言,数组)

//快速排序
void quickSort(int nums[], int left, int right){
	if(left >= right){
		return;//递归结束条件 
	}
	//进行一次划分,获得基准值的下标
	int partitionIndex = partition(nums, left, right);
	//对左侧进行划分排序
	quickSort(nums, left, partitionIndex-1);
	//对右侧进行划分排序
	quickSort(nums, partitionIndex+1, right); 
}

//进行一次划分,并返回划分后的基准值所在的下标 
int partition(int nums[], int left, int right){ 
	//设置并暂存基准值(以第一个元素left为基准值) 
	int temp = nums[left];
	while(left < right){ 
		//向左找到比temp小的数 
		while(left < right && nums[right] > temp){
			right--;
		}
		if(left < right){
			nums[left] = nums[right];
		} 
		//向右走,找比temp大的数 
		while(left < right && nums[left] < temp){
			left++;
		}
		if(left < right){
			nums[right] = nums[left];
		}
		
	}//left和right相遇,退出while循环 
	nums[left] = temp; 
	//返回基准值
	return left;
} 

堆排序

算法思想

堆排序是利用堆这一数据结构排序的算法,(堆的特点:堆近似于完全二叉树,且子结点的值总小于或大于父节点的值,分别为大根堆、小根堆)。先建立大根堆,将堆顶元素和堆尾元素互换,堆长度减一,调整堆顶元素,使其保持大根堆,重复执行以上动作,直至堆长度为一。

算法评价

平均时间复杂度:O(nlogn)

代码实现(C语言、数组)

//堆排序 
void heapSort(int nums[], int n){
	//建立大根堆 
	buildMaxHeap(nums, n);
	//依次将大根堆顶的元素交换到底端,并调整顶端元素,使其依旧为大根堆
	int len = n;//待调整元素个数 
	while(len >= 0){
		//交换顶端元素到底端
		swap(nums, 0, len-1);
		len--;//调整长度减一 
		//调整顶端元素,保持它是大根堆 
		heapIfy(nums, 0, len); 
	} 
}
 
//建立大根堆
void buildMaxHeap(int nums[], int n){
	int pos = n/2 - 1;//待调整位置(下标从0开始,故-1) 
	int maxPos;//三个结点中的最大值的位置 
	for(; pos >= 0; pos--){
		heapIfy(nums, pos, n); 
	}
}

//堆调整 数组 要调整的位置,能调整的长度 
void heapIfy(int nums[], int i, int len){
	int leftChild = i*2 + 1; //因数组下标从0开始,所以leftChild,rightChild都要+1 
	int rightChild = i*2 + 2;
	int max = i;
	//找到三者中的最大值的位置 
	if(leftChild < len && nums[max] < nums[leftChild]){
		max = leftChild;
	}
	if(rightChild < len && nums[max] < nums[rightChild]){
		max = rightChild;
	}
	//i不是最大值所在的位置,进行调整 
	if(max != i){
		swap(nums, max, i);
		heapIfy(nums, max, len); 
	}
} 

//交换数组中pos1和pos2的位置的元素 
void swap(int nums[], int pos1, int pos2){
	int temp = nums[pos1];
	nums[pos1] = nums[pos2];
	nums[pos2] = temp;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值