首页 > 编程语言 >算法学习笔记5: 排序算法

算法学习笔记5: 排序算法

时间:2024-10-30 14:19:50浏览次数:3  
标签:idx int while 笔记 算法 数组 child 排序

排序算法

归并排序

时间复杂度O(nlogn) 空间复杂度O(n),稳定排序

就是给定两个有序数组,将两个数组合并在一起升序。

定义一个更大的数组,给定两个指针分别指向两个数组,每次取较小值放入新数组。

void mergeSort(int a[],int l,int r){
	
	if(l>=r)return;
	int mid=l+r>>1;
    //分离数组
	mergeSort(a,l,mid);
	mergeSort(a,mid+1,r);
	//合并l-r范围内的数组 
	int i=l,j=mid+1,k=0;
	while(i<=mid&&j<=r){
		if(a[i]<a[j])tmp[k++]=a[i++];
		else tmp[k++]=a[j++];
	}
	//将剩余的数直接添加到序列的后面 
	while(i<=mid)tmp[k++]=a[i++];
	while(j<=r)tmp[k++]=a[j++];
	//拷贝到原数组
	k=0;
	for(int i=l;i<=r;i++){
		a[i]=tmp[k++];
	} 
}

快速排序

快速排序的思想就是找到一个基准值,把序列分成两个部分,左半部分大于等于基准值,右半部分小于等于基准值。

然后对左右部分分别进行递归排序。

最差时间复杂度O(n^2) 和冒泡排序一样,平均时间复杂度 O(n*logn)不稳定排序

void quickSort(int a[],int l,int r){
	if(l>=r)return;
	int i=l-1,j=r+1;
	//选取基准值
	int std=a[l+r>>1];
	while(i<j){
        //为了考虑边界问题,边界问题有很多,直接找个正确的模板背过即可
		while(a[--j]>std);
		while(a[++i]<std);
		if(i<j)swap(a[i],a[j]);
	}
	quickSort(a,l,j);//对左边排序 
	quickSort(a,j+1,r);//对右边排序 
	
}

快速选择查找

快速选择查找就是基于快速排序,只对包含第k个值的区间排序,不需要排序整个数组

平均时间复杂度为O(n),最坏时间复杂度为O(n^2)

//快速选择排序算法
void sort(int a[],int l,int r){
	
	if(l>=r)return;
	int i=l-1,j=r+1;
	int std=a[l+r>>1];
	while(i<j){
		while(a[--j]>std);
		while(a[++i]<std);
		if(i<j)swap(a[i],a[j]);
	} 
	if(j>=k-1)sort(a,l,j);
	else sort(a,j+1,r);
}

桶排序

不基于比较的排序算法

通过统计值域内每个数据的个数,然后根据个数排序

int count[1002];//存放数的个数 这里数的值域是[0,1000]
void bucketSort(int n){
    //统计每个数据的个数
	for(int i=0;i<n;i++){
		count[num[i]]++;
	}
	int cnt=0;
    //值域为[0,1000]
	for(int i=0;i<=1000;i++){
		while(count[i]!=0){
			num[cnt++]=i;//将数填回原数组
			count[i]--;
		}
	}
}

堆排序(升序)

时间复杂度 O(nlogn),不稳定排序

空间复杂度 O(1)

//对某个根节点调整为大根堆
//从上往下进行调整
void adjust_down(int *a,int n,int i){//i是需要调整的根节点的下标
	int father=i;
	int child=i*2+1;
	while(child<n){
        //比较孩子结点的大小,选出较大的那个
		if((child+1)<=n-1&&a[child]<=a[child+1]) ++child;
        //交换父节点和孩子结点,并顺着孩子结点向下继续调整
		if(a[father]<a[child]){
			int temp;
			temp=a[child];
			a[child]=a[father];
			a[father]=temp;
			father=child;
			child=father*2+1;
		}else{
            //一旦不能继续调整就退出循环
			break;
		}
	}
	
}


void heap_sort(int *a,int n){
	//建立大根堆
    //(n-1)/2为从后往前,第一个有孩子的结点
	for(int i=(n-1)/2;i>=0;i--){
		adjust_down(a,n,i);
	} 
	//摘取大顶,与最后一个结点交换 
	for(int i=0;i<n-1;i++){
		int temp=a[0];
		a[0]=a[n-i-1];
		a[n-i-1]=temp;
		adjust_down(a,n-i-1,0);
	} 
}

堆模拟

以小根堆为例:

插入操作:插入到末尾,并向上调整。

删除第k个插入的元素:用末尾元素替代。并向上调整或向下调整(只会执行一个)

修改第k个插入的元素:修改后,向上调整或向下调整(只会执行一个)

下面展示调整代码:

/*
	为了能够维护数组下标和插入顺序的映射关系,这里引入两个辅助数组
	get_idx[u]用来获得数组下标为u的插入次序.
	get_index[idx]用来获得第idx个插入的数组的下标(在数组中的位置)
	这里的idx和链表、Trie数组中的idx作用类似。按道理,应该按照结构体的方式来实现这些数据结构的,但是做算法题一般用数组模拟,主要是因为比较快。原来这两个属性都是以结构体的方式联系在一起的,现在如果用数组模拟,就利用idx联系节点的属性(w、ne、e)
*/
//节点交换
void heap_swap(int a,int b){
	//先维护序号和数组下标的数组
	swap(get_index[get_idx[a]],get_index[get_idx[b]]);
	swap(get_idx[a],get_idx[b]);
	swap(num[a],num[b]);
}
//向上调整 
void adjust_up(int i){
	int child=i;
	int fa=child/2;
	while(fa && num[child]<num[fa]){
	    heap_swap(child,fa);
		child=fa;
		fa=child/2;
	}
}
//向下调整
void adjust_down(int i){
	int fa=i;
	int child=2*i;
	while(child<=siz){
		if(child+1<=siz && num[child]>num[child+1])child++;
		if(num[fa]>num[child]){
			heap_swap(fa,child);
			fa=child;
			child=2*fa;
		}else break;
	}
}

标签:idx,int,while,笔记,算法,数组,child,排序
From: https://blog.csdn.net/yyyyyyuzy/article/details/143329087

相关文章

  • 算法学习笔记6: 字符串
    字符串字符串哈希通过求解字符串前缀的哈希值的方式,可以比较字符串内任意字串的相等情况。首先需要把每个字符映射成数字,是什么无所谓(因为字符不好计算哈希值呀),然后类似于计算前缀和的方式,这里是计算h[i]表示前i个字符的哈希值。然后把要计算的每个前缀字符串看作是一个P......
  • 【笔记】【Android】Activity的Task模式
    【笔记】【Android】Activity的Task模式笔记系列,内容是从网络搜索的结果,不一定是正确的理解。如果存在谬误,欢迎大家指正。Task一个应用可能会包含多个Activity,管理这些Activity顺序的容器,就是Task。当Activity1拉起Activity2时,Task会将Activity2压栈,将显示Activity2的内容。......
  • 快速排序算法
    快速排序算法是一种高效的排序算法,由C.A.R.Hoare在1960年提出。它的基本思想是分而治之,通过一趟排序将待排序的元素分割成两个部分,其中一部分的所有元素都比另一部分的所有元素小,然后递归地对这两部分继续进行排序操作,整个排序过程可以递归进行,以达到整个数据变成有序序列。快......
  • JavaScript基础知识——黑马JavaWeb学习笔记
    JavaScript基础JavaScript:跨平台、面向对象的脚本语言(脚本语言:不需要编译,浏览器解释完直接运行)作用:控制网页行为,使网页可交互ps:JavaScript与Java是两门完全不同的语言本文为学习黑马程序员JavaWeb开发教程中JS部分学习笔记文章目录JavaScript基础一、JS引入方式1.......
  • SQL注入语句笔记(很全,持续更新ing)
    SQL注入原理:1.参数用户可控化:前端传递给后端的参数是用户可以控制的2.参数带入数据库查询:传入的参数拼接到SQL语句,且带入数据库查询sql注入常用知识:1.information_schema:表示所有信息,包括库、表、列2.information_schema.tables:记录所有表名信息的表3.information_sch......
  • 代码随想录算法训练营第十三天
    1二叉树的理论基础文章链接:代码随想录视频链接:关于二叉树,你该了解这些!|二叉树理论基础一网打尽,二叉树的种类、二叉树的存储方式、二叉树节点定义、二叉树的遍历顺序_哔哩哔哩_bilibili1.1二叉树的种类满二叉树所有节点处的值都排满了,没有空的完全二叉树只有在最后一......
  • 基于模型预测算法的混合储能微电网双层能量管理系统研究(Matlab代码实现)
      ......
  • 【无人机】基于GWO算法、MP-GWO灰狼算法、灰狼-布谷鸟优化算法、CS-GWO多种群灰狼优化
        ......
  • python毕业设计django基于协同过滤算法的养老新闻推荐网站
    文章目录前言一、项目介绍三、功能介绍四、核心代码五、效果图前言Django基于协同过滤算法的养老新闻推荐网站是一个结合了Django框架和协同过滤推荐算法的养老领域信息服务系统。该系统旨在通过个性化推荐算法,向用户推荐符合其兴趣偏好的养老新闻,以提高用户体验和......
  • 代码随想录算法训练营第六天| leetcode242.有效的字母异位词、leetcode349.两个数组的
    1.leetcode242.有效的字母异位词题目链接:242.有效的字母异位词-力扣(LeetCode)文章链接:代码随想录视频链接:学透哈希表,数组使用有技巧!Leetcode:242.有效的字母异位词哔哩哔哩bilibili自己的思路:首先就是对字符串进行分开成一个一个单独的字母,然后使用列表存储这些数据,再对......