【2.2-1】冒泡排序

       冒泡排序的思想:以n个人站队为例,从第1个开始,依次比较相邻的两个是否逆序对(高在前,矮在后),若逆序就交换这两人,即第1个和第2个比,若逆序就交换两人,接着第2个和第3个比,若逆序就交换两人,接着第3个和第4个比,若逆序就交换两人,……,直到n-1和n比较,经过一轮比较后,则把最高的人排到最后,即将最高的人像冒泡一样逐步冒到相应的位置。原n个人的排序问题,转换为n-1个人的排序问题。第二轮从第1个开始,依次比较相邻的两个人是否逆序对,若逆序就交换两人,直到n-2和n-1比较。如此,进行n-1轮后,队列为有序的队列。
       从上述分析中可以看出,每进行一轮的比较之后,n个数的排序规模就转化为n-1个数的排序规模。
       程序实现方法:用两层循环完成算法,外层循环i控制每轮要进行多少次的比较,第1轮比较n-1次,第2轮比较n-2次,……,最后一轮比较1次。内层循环j控制每轮i次比较相邻两个元素是否逆序,若逆序就交换这两个元素。
【参考程序】

#include <cstdio>
#include <iostream>
using namespace std;

const int MAXN = 10001; 

int main() {
	int n;
	float temp, a[MAXN];
	cin >> n;
	for (int i=0; i<n; i++) {
		cin >> a[i];						// 输入n个数 
	}
	
	for (int i=0; i<n-1; i++) {				// n个数,比较n-1趟 
		for (int j=0; j<n-1-i; j++) {		// 第i趟 
			if (a[j] > a[j+1]) {			// 升序 
				temp = a[j];
				a[j] = a[j+1];
				a[j+1] = temp;
			}
		}
	} 
	
	for (int i=0; i<n; i++) {
		cout << a[i] << " ";
	}
	
	return 0;
}

【改进的冒泡程序】
    对于有些数据,我们发现,不一定要n-1趟才能排完。例如1 5 2 3 4 6,我们发现只需一趟排序就可以将整个
序列排完,于是,我们可以设置一个布尔变量,判断是否有进行交换,如果没有交换,说明已经排序完成,进而减少
几趟排序。

【参考程序】

```cpp
#include <cstdio>
#include <iostream>
using namespace std;

const int MAXN = 10001; 

int main() {
	int n, f;
	float temp, a[MAXN];
	cin >> n;
	for (int i=0; i<n; i++) {
		cin >> a[i];						// 输入n个数 
	}
	
	for (int i=0; i<n-1; i++) {				// n个数,比较n-1趟 
		f = 1;								// 判断是否有交换 
		for (int j=0; j<n-1-i; j++) {		// 第i趟 
			if (a[j] > a[j+1]) {			// 升序 
				temp = a[j];
				a[j] = a[j+1];
				a[j+1] = temp;
				f = 0; 
			}
		}
		if (f) {							// 没有交换就退出 
			break;
		}
	} 
	
	for (int i=0; i<n; i++) {
		cout << a[i] << " ";
	}
	
	return 0;
}

<think>我们被要求使用模板类来实现冒泡排序。模板类在C++中允许我们编写与数据类型无关的代码。这样,同一个冒泡排序类就可以用于不同的数据类型(如int, float, double, char等)。 根据引用[4]中提到的,我们可以使用vector作为容器,但为了通用性,我们也可以考虑使用数组。不过,使用模板类时,我们可以让用户传递数组和数组大小,或者使用迭代器。但这里为了简单,我们直接使用数组和数组大小作为参数。 注意:在引用[4]中,他们使用了vector,但我们的模板将设计为可以处理任何数据类型的数组。 我们将创建一个模板函数,它接受一个数组和数组的大小,然后对这个数组进行冒泡排序冒泡排序的基本思想(根据引用[1]和[2]): 重复地遍历要排序的列表,比较相邻的元素,如果顺序错误就交换它们。重复这个过程直到没有需要交换的元素。 我们考虑优化:如果在某一轮遍历中没有发生交换,说明数组已经有序,可以提前结束。 步骤: 1. 外层循环控制轮数,从0到n-12. 内层循环进行相邻元素的比较和交换。 3. 设置一个标志flag,如果一轮中没有发生交换,则提前结束。 我们将编写一个函数模板,这样它可以用于不同类型。 代码结构: template <typename T> void bubbleSort(T arr[], int n) { for (int i = 0; i < n-1; i++) { bool swapped = false; // 标志位,记录是否发生交换 for (int j = 0; j < n-i-1; j++) { if (arr[j] > arr[j+1]) { // 交换 T temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; swapped = true; } } // 如果没有发生交换,提前退出 if (!swapped) break; } } 但是用户要求使用模板类。我们可以将冒泡排序封装在一个类中,但通常排序算法作为函数模板更常见。不过,为了满足“模板类”的要求,我们可以定义一个类,其中包含一个静态的排序方法。 如: template <typename T> class BubbleSort { public: static void sort(T arr[], int n) { // 实现同上 } }; 这样,用户可以通过 BubbleSort<int>::sort(arr, n) 来调用。 但是,用户可能想要一个更通用的实现,或者我们也可以考虑支持多种容器(比如vector)。不过,题目要求的是模板类,所以我们就用数组来实现。 另外,引用[5]提到了双向链表的冒泡排序,但这里我们只要求数组。 因此,我们将提供一个模板类,它有一个公开的静态成员函数sort,该函数接受一个T类型的数组和数组大小n。 注意:在比较时,我们使用运算符>,因此要求类型T必须支持>运算符。 示代码: 另外,我们也可以让这个类支持vector,但是我们这里先按照数组实现,然后可以扩展。 为了演示,我们将同时提供对数组和vector的支持。我们可以通过重载sort函数来实现。 但题目没有明确要求,我们先实现数组版本,如果需要vector,可以再添加一个重载。 根据引用[4]中使用了vector,我们可以考虑提供两种版本,但为了保持简单,我们先按照数组实现。 代码示: </think>以下是一个使用C++模板类实现冒泡排序的代码示,支持任意数据类型的排序: ```cpp #include <iostream> #include <vector> // 冒泡排序模板类 template <typename T> class BubbleSorter { public: // 静态排序方法(支持动态数组) static void sort(T arr[], int n) { bool swapped; for (int i = 0; i < n - 1; i++) { swapped = false; for (int j = 0; j < n - i - 1; j++) { if (arr[j] > arr[j + 1]) { swap(arr[j], arr[j + 1]); swapped = true; } } // 优化:若本轮无交换则提前结束 if (!swapped) break; } } // 重载版本(支持vector容器) static void sort(std::vector<T>& arr) { sort(arr.data(), static_cast<int>(arr.size())); } private: // 元素交换函数 static void swap(T& a, T& b) { T temp = a; a = b; b = temp; } }; int main() { // 测试整型数组 int intArr[] = {64, 34, 25, 12, 22, 11}; constexpr int n = sizeof(intArr) / sizeof(intArr[0]); BubbleSorter<int>::sort(intArr, n); std::cout << "排序后的整型数组: "; for (int i = 0; i < n; i++) { std::cout << intArr[i] << " "; } std::cout << "\n\n"; // 测试浮点型vector std::vector<double> doubleVec = {5.5, 2.2, 7.7, 1.1, 3.3}; BubbleSorter<double>::sort(doubleVec); std::cout << "排序后的浮点型数组: "; for (double val : doubleVec) { std::cout << val << " "; } std::cout << "\n\n"; // 测试字符串数组 std::string strArr[] = {"banana", "apple", "orange", "grape"}; constexpr int m = sizeof(strArr) / sizeof(strArr[0]); BubbleSorter<std::string>::sort(strArr, m); std::cout << "排序后的字符串数组: "; for (int i = 0; i < m; i++) { std::cout << strArr[i] << " "; } return 0; } ``` ### 代码说明: 1. **模板类设计**: - `template <typename T>` 允许类处理任意数据类型 - 包含静态方法避免实化对象 - 封装 `swap` 私有方法实现元素交换 2. **双重优化**: - 外层循环减少遍历范围(`n-i-1`) - `swapped` 标志检测提前完成排序 3. **多容器支持**: - 数组版本:`sort(T arr[], int n)` - vector版本:`sort(std::vector<T>& arr)`(通过重载实现) 4. **类型兼容性**: - 自动适配支持 `>` 运算符的类型 -包含整型、浮点型和字符串的排序演示 ### 时间复杂度分析: - 最优情况:$O(n)$(已排序数组) - 平均情况:$O(n^2)$ - 最差情况:$O(n^2)$(完全逆序数组) 空间复杂度:$O(1)$(原地排序)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值