最小的K个数

问题描述:

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

思路:

通过排序,将n个数变为有序序列后再输出前k个数。以下实现了七种排序方法:

#include<iostream>
#include<vector>
using namespace std;
/*对于排序算法,排序前后,两个相等的数相对位置不变,则算法稳定;
不稳定指的是排序前后两个相等的数相对位置发生了变化*/
class Solution {
public:
	/*在C++里很多时候我们会遇到函数想返回两个以上结果的情况,这时候可以用数组(vector)、类来作为容器返回,也可以声明一个全局变量的数组,将数值存放在数组里解决。
		第一个方式是使用引用来解决,将vector的引用在函数间传递,对于input这个vector进行排序,需要传递引用,这样被调函数中排完序的数组才能和调用函数共用*/

	/*快速排序:平均时间复杂度o(nlogn),不稳定
	通过一趟排序将序列分为左右两部分,其中左半部分的值均比右半部分的值小
	然后分别对左右部分的记录进行排序,直到整个序列有序
	*/
	int partition(vector<int> &a, int low, int high) {
		int key = a[low];  //初始以低位上的数字作为分割线分割出左右两部分
		while (low<high) {
			while (low<high&&a[high] >= key) high--;  //从最右端依次判断右端元素是否大于等于分割数字,如果大于等于,high--
			a[low] = a[high];   //当a[high]<key时,这个值属于左端
			while (low<high&&a[low] <= key) low++;
			a[high] = a[low];
		}
		a[low] = key;   //key应位于最终low的位置上
		return low;
	}
	void quick_sort(vector<int> &a, int low, int high) {
		if (low >= high) return;
		int keypos = partition(a, low, high);
		quick_sort(a, low, keypos - 1);
		quick_sort(a, keypos + 1, high);
	}
	/*冒泡排序:平均时间复杂度o(n^2),稳定
	比较相邻的元素,如果第一个比第二个大,就交换他们两个
	针对所有元素重复以上步骤,除了最后一个*/
	void bubble_sort(vector<int> &a) {
		for (int i = 0; i < a.size()-1; i++) {
			for (int j = 0; j < a.size() - 1 - i; j++) {
				if (a[j] > a[j + 1]) {
					int temp = a[j];
					a[j] = a[j + 1];
					a[j + 1] = temp;
				}
			}
		}
	}

	/*插入排序:平均时间复杂度o(n^2),稳定
	将一个记录插入到已排序的有序表中,得到一个新的,记录数增1的有序表
	*/
	void insert_sort(vector<int> &a) {
		for (int i = 1; i < a.size(); i++) {
			int key = a[i];   //当前值
			int j = i - 1;
			while (j >= 0 && a[j] > key) {    //当已排好序的元素大于当前要插入的元素,就进行后移,把a[j]的值移到a[j+1]
				a[j + 1] = a[j];
				j--;
			}
			a[j + 1] = key;    //当不满足上述条件跳出while循环后证明a[j]<key,所以a[j+1]就是最终key所在的位置
		}
	}
	/*shell排序:平均时间复杂度o(n^1.3),不稳定
	希尔排序是插入排序的一种高效实现,也叫缩小增量排序。
	先将整个待排记录序列分割为若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时再对全体记录进行一次直接插入排序
	将相隔某个“增量”的记录组成一个子序列
	*/
	void shell_insert(vector<int> &a, int d) {
		for (int i = d; i < a.size(); i++) {
			int key = a[i];
			int j = i - d;
			while (j >= 0 && a[j] > key) {
				a[j + d] = a[j];
				j = j - d;
			}
			a[j + d] = key;
		}
	}
	void shell_sort(vector<int> &a) {
		int d = a.size() / 2;    //间隔值
		while (d >= 1) {
			shell_insert(a, d);
			d = d / 2;
		}
	}

	/*选择排序:平均时间复杂度o(n^2),不稳定
	选择排序每次在确定了最小数的下标之后再进行交换,减少交换次数
	*/
	void select_sort(vector<int> &a) {
		for (int i = 0; i < a.size() - 1; i++) {
			int minIndex = i;
			for (int j = i; j < a.size(); j++) {
				if (a[j] < a[minIndex]) minIndex = j;
			}
			if (minIndex != i) {
				int temp = a[i];
				a[i] = a[minIndex];
				a[minIndex] = temp;
			}
		}
	}
	/*堆排序:平均时间复杂度o(nlogn),不稳定
	堆是完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。因此,若一个序列是堆,则堆顶元素必为序列中n个元素的最小值(或最大值)
	堆排序需要解决的两个问题:(1)如何由一个无序序列建成一个堆?(2)如何在输出堆顶元素之后,调整剩余元素成为一个新的堆?
	假设序列有n个元素,先将这n个元素建成大顶堆,然后取堆顶元素,与序列第n个元素交换,然后调整前n-1个元素,使其重新成为堆
	*/
	/*当数组下标从0开始时,结点下标为i时,其左节点为2*i+1,右节点为2*i+2 */
	void heapAdjust(vector<int> &a, int s, int m) {
		int key = a[s];
		for (int j = 2 * s + 1; j <= m; j = 2 * j + 1) {   //从当前位置s的左节点开始
			if (j < m && a[j] <= a[j + 1]) {
				j++;      //当j不超过数组长度时,找到左右节点中较大的那个
			}
			if (a[j] < key) break;  //若较大的那个结点还是小于父节点,跳出for循环
			a[s] = a[j];
			s = j;          //否则父节点与子结点交换
		}
		a[s] = key;
	}
	void heap_sort(vector<int> &a) {
		//初始建堆,从第一个非叶子结点开始,建好堆后堆顶为最大元素
		for (int i = a.size() / 2 - 1; i >= 0; i--) {
			heapAdjust(a, i, a.size() - 1);
		}
		//取堆顶元素,并且调整
		for (int i = a.size()-1; i >= 0; i--) {
			int temp = a[i];
			a[i] = a[0];
			a[0] = temp;
			heapAdjust(a,0,i-1);
		}
	}
	/*归并排序:平均时间复杂度o(nlogn),稳定
	把有序表划分成元素个数尽量相等的两半
	把两半元素分别排序
	把两个有序表合并成一个
	*/
	void merge(vector<int> &a, int first, int mid, int last) {
		vector<int> temp(last - first + 1);    //定义一个辅助数组
		int copyIndex = last - first;          //开始复制的位置
		int i = mid, j = last;
		while (i >= first && j >= mid + 1) {
			if (a[i] > a[j]) temp[copyIndex--] = a[i--];
			else temp[copyIndex--] = a[j--];
		}
		while (i >= first) temp[copyIndex--] = a[i--];
		while (j >= mid + 1) temp[copyIndex--] = a[j--];
		for (int k = first; k <= last; k++) {
			a[k] = temp[k-first];
		}
	}
	void merge_sort(vector<int> &a,int first,int last) {
		if (first >= last) return;
		int mid = (first + last) / 2;
		merge_sort(a, first, mid);
		merge_sort(a, mid + 1, last);
		merge(a, first, mid, last);
	}

	vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
		vector<int> vk;
		if (input.size() == 0 || k>input.size()) {
			return vk;
		}
		//quick_sort(input, 0, input.size() - 1);
		//bubble_sort(input);
		
		//insert_sort(input);
		//shell_sort(input);

		//select_sort(input);
		//heap_sort(input);
		merge_sort(input, 0, input.size() - 1);
		for (int i = 0; i<input.size(); i++) {
			cout << input[i] << " ";
		}
		cout << endl;
		for (int i = 0; i<k; i++) {
			vk.push_back(input[i]);
		}
		return vk;
	}
};
int main() {
	vector<int> v = { 4,5,1,6,2,7,3,0 };
	Solution s;
	vector<int> result;
	result=s.GetLeastNumbers_Solution(v, 4);
	for (int i = 0; i < 4; i++) {
		cout << result[i] << " ";
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
GeoPandas是一个开源的Python库,旨在简化地理空间数据的处理和分析。它结合了Pandas和Shapely的能力,为Python用户提供了一个强大而灵活的工具来处理地理空间数据。以下是关于GeoPandas的详细介绍: 一、GeoPandas的基本概念 1. 定义 GeoPandas是建立在Pandas和Shapely之上的一个Python库,用于处理和分析地理空间数据。 它扩展了Pandas的DataFrame和Series数据结构,允许在其存储和操作地理空间几何图形。 2. 核心数据结构 GeoDataFrame:GeoPandas的核心数据结构,是Pandas DataFrame的扩展。它包含一个或多个列,其至少一列是几何列(geometry column),用于存储地理空间几何图形(如点、线、多边形等)。 GeoSeries:GeoPandas的另一个重要数据结构,类似于Pandas的Series,但用于存储几何图形序列。 二、GeoPandas的功能特性 1. 读取和写入多种地理空间数据格式 GeoPandas支持读取和写入多种常见的地理空间数据格式,包括Shapefile、GeoJSON、PostGIS、KML等。这使得用户可以轻松地从各种数据源加载地理空间数据,并将处理后的数据保存为所需的格式。 2. 地理空间几何图形的创建、编辑和分析 GeoPandas允许用户创建、编辑和分析地理空间几何图形,包括点、线、多边形等。它提供了丰富的空间操作函数,如缓冲区分析、交集、并集、差集等,使得用户可以方便地进行地理空间数据分析。 3. 数据可视化 GeoPandas内置了数据可视化功能,可以绘制地理空间数据的地图。用户可以使用matplotlib等库来进一步定制地图的样式和布局。 4. 空间连接和空间索引 GeoPandas支持空间连接操作,可以将两个GeoDataFrame按照空间关系(如相交、包含等)进行连接。此外,它还支持空间索引,可以提高地理空间数据查询的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值