Swap in array

本文介绍了一种算法,该算法可在单次遍历中检测给定数组是否能通过一次元素交换变为非递减序列。通过对数组进行扫描并记录可能的交换位置,算法能够高效地确定所需条件是否满足。

Question:

Given an array, detect whether can make it non-decreasing with only one swap operation in a single traverse.

Example:

3  1 3 4            false
5  1 3 2 4 5        true
5  5 2 3 4 1        true
5  2 1 3 4 6        true
5  1 3 7 4 5        false
5  1 6 9 12 3       false
7  1 2 4 10 8 7 11   true
6  1 2 3 6 5 4      true
6  1 2 10 4 8 7     false
7  1 2 4 10 8 7 9     false
7  1 3 7 2 9 13 14    false
9  1 2 5 3 7 9 8 14 16   false
10 1 2 5 3 7 9 8 14 17 16   false

Solution:

public class SwapInArray {
	public static void main(String[] args) {
		int[] nums = null;
		try {
			File myFile = new File("test.txt");
			FileReader fileReader = new FileReader(myFile);
			BufferedReader reader = new BufferedReader(fileReader);
			String line = null;
			int j = 1;
			while ((line = reader.readLine()) != null && (line.length() != 0)) {
				StringReader l = new StringReader(line);
				Scanner scanner = new Scanner(l);
				int size = scanner.nextInt();
				nums = new int[size];
				for (int i = 0; i < size; i++) {
					nums[i] = scanner.nextInt();
				}
				System.out.print(j++ + ": ");
				boolean v = swap2Ace(nums);
				System.out.println(v);
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
		
	}
	static boolean swap2Ace (int[] nums) {
		if (nums == null || nums.length == 0) {
			return false;
		}
		int front = -1;
		int end = -1;
		for (int i = 0; i < nums.length - 1; i++) {
			if (nums[i] > nums[i + 1]) {
				if (end != -1) {
					return false;
				}
				if (front == -1 ) {
					front = i;
				} else {
					end = i + 1;
				}
			}
		}
		System.out.print(front + " " + end + " ");
		if (front == -1) {
			return false;
		}
		if (end == -1) {
			if (front - 1 >= 0) {
				if (nums[front - 1] > nums[front + 1]) {
					return false;
				}
			}
			if (front + 2 < nums.length) {
				if (nums[front] > nums[front + 2]) {
					return false;
				}
			}
		} else {
			if (front - 1 >= 0) {
				if (nums[front - 1] > nums[end]) {
					return false;
				}
			}
			if (nums[front + 1] < nums[end]) {
				return false;
			}
			if (end + 1 < nums.length) {
				if (nums[front] > nums[end + 1]) {
					return false;
				}
			}
			if (nums[front] < nums[end - 1]) {
				return false;
			}
		}
		return true;
	}
}

思路:

1. 读入测试文件。File,FileReader, BufferedReader, StringReader, Scanner.

2. 检测断点,最多有两个断点。如果多于两个则肯定不能通过一次交换完成。如果只有一个断点,则判断它与它后面的交换后是否满足条件(只比较后面第一个即可,不可能与后面第二个交换,因为后面第二个肯定比后面第一个大)。如果有两个断点,则判断这两个断点交换后能否满足条件。

module input_8_generator ( input wire clk, input wire rst_n, input wire [63:0] data_in, // 使用packed数组,8个8位数据拼接成64位 output reg [63:0] data_out // 使用packed数组 ); // 比较并交换模块 function [15:0] compare_and_swap; input [7:0] a; input [7:0] b; input dir; if (dir == (a > b)) begin compare_and_swap = {a, b}; // a在前,b在后 end else begin compare_and_swap = {b, a}; // b在前,a在后 end endfunction // 从64位输入中提取8个8位数据 wire [7:0] data_in_array [7:0]; assign data_in_array[0] = data_in[63:56]; assign data_in_array[1] = data_in[55:48]; assign data_in_array[2] = data_in[47:40]; assign data_in_array[3] = data_in[39:32]; assign data_in_array[4] = data_in[31:24]; assign data_in_array[5] = data_in[23:16]; assign data_in_array[6] = data_in[15:8]; assign data_in_array[7] = data_in[7:0]; // 双调排序阶段 wire [7:0] stage1 [7:0]; wire [7:0] stage2 [7:0]; wire [7:0] stage3 [7:0]; // 临时连线用于函数返回值 wire [15:0] temp [7:0]; // 第一阶段 assign temp[0] = compare_and_swap(data_in_array[0], data_in_array[1], 1'b0); assign temp[1] = compare_and_swap(data_in_array[2], data_in_array[3], 1'b0); assign temp[2] = compare_and_swap(data_in_array[4], data_in_array[5], 1'b0); assign temp[3] = compare_and_swap(data_in_array[6], data_in_array[7], 1'b0); assign temp[4] = compare_and_swap(data_in_array[0], data_in_array[1], 1'b1); assign temp[5] = compare_and_swap(data_in_array[2], data_in_array[3], 1'b1); assign temp[6] = compare_and_swap(data_in_array[4], data_in_array[5], 1'b1); assign temp[7] = compare_and_swap(data_in_array[6], data_in_array[7], 1'b1); // 分配第一阶段结果 assign stage1[0] = temp[0][15:8]; assign stage1[1] = temp[0][7:0]; assign stage1[2] = temp[1][15:8]; assign stage1[3] = temp[1][7:0]; assign stage1[4] = temp[2][15:8]; assign stage1[5] = temp[2][7:0]; assign stage1[6] = temp[3][15:8]; assign stage1[7] = temp[3][7:0]; // 第二阶段 wire [15:0] temp2 [7:0]; assign temp2[0] = compare_and_swap(stage1[0], stage1[2], 1'b0); assign temp2[1] = compare_and_swap(stage1[1], stage1[3], 1'b0); assign temp2[2] = compare_and_swap(stage1[4], stage1[6], 1'b0); assign temp2[3] = compare_and_swap(stage1[5], stage1[7], 1'b0); assign temp2[4] = compare_and_swap(stage1[0], stage1[2], 1'b1); assign temp2[5] = compare_and_swap(stage1[1], stage1[3], 1'b1); assign temp2[6] = compare_and_swap(stage1[4], stage1[6], 1'b1); assign temp2[7] = compare_and_swap(stage1[5], stage1[7], 1'b1); assign stage2[0] = temp2[0][15:8]; assign stage2[1] = temp2[0][7:0]; assign stage2[2] = temp2[1][15:8]; assign stage2[3] = temp2[1][7:0]; assign stage2[4] = temp2[2][15:8]; assign stage2[5] = temp2[2][7:0]; assign stage2[6] = temp2[3][15:8]; assign stage2[7] = temp2[3][7:0]; // 第三阶段 wire [15:0] temp3 [7:0]; assign temp3[0] = compare_and_swap(stage2[0], stage2[4], 1'b0); assign temp3[1] = compare_and_swap(stage2[1], stage2[5], 1'b0); assign temp3[2] = compare_and_swap(stage2[2], stage2[6], 1'b0); assign temp3[3] = compare_and_swap(stage2[3], stage2[7], 1'b0); assign temp3[4] = compare_and_swap(stage2[0], stage2[4], 1'b1); assign temp3[5] = compare_and_swap(stage2[1], stage2[5], 1'b1); assign temp3[6] = compare_and_swap(stage2[2], stage2[6], 1'b1); assign temp3[7] = compare_and_swap(stage2[3], stage2[7], 1'b1); assign stage3[0] = temp3[0][15:8]; assign stage3[1] = temp3[0][7:0]; assign stage3[2] = temp3[1][15:8]; assign stage3[3] = temp3[1][7:0]; assign stage3[4] = temp3[2][15:8]; assign stage3[5] = temp3[2][7:0]; assign stage3[6] = temp3[3][15:8]; assign stage3[7] = temp3[3][7:0]; // 将结果数组拼接成64位输出 wire [63:0] stage3_packed; assign stage3_packed = {stage3[0], stage3[1], stage3[2], stage3[3], stage3[4], stage3[5], stage3[6], stage3[7]}; // 输出寄存器 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin data_out <= 64'b0; end else begin data_out <= stage3_packed; end end endmodule根据上述代码生成test代码
09-24
<think>我们注意到用户提供了几个引用,其中引用[1]和引用[2]是关于快速排序的C语言实现和原理说明。用户要求将包含QuickSort函数的代码片段改写成C语言代码,但并没有给出具体的代码片段。不过,根据上下文,用户可能是想让我们参考引用[1]和引用[2]中的快速排序实现,提供一个优化后的C语言版本。 根据之前的对话,我们已经给出了一个随机基准的快速排序实现。但用户引用的代码片段中,引用[1]的代码使用的是固定基准(第一个元素)和挖坑法(或者说Hoare分区法的变种)实现。因此,我们可以根据用户提供的引用[1]中的代码,改写成一个标准的C语言快速排序,同时也可以考虑加入随机基准的优化。 引用[1]中的快速排序代码: ```c void quicksort(int a[], int left, int right) { if (left < right) { int i = left; int j = right; int pivot = a[left]; //选取第一个元素作为基准 while (i < j) { while (i < j && a[j] >= pivot) //从右向左找到第一个小于基准的元素 j--; if (i < j) a[i++] = a[j]; //将该元素放到左边 while (i < j && a[i] <= pivot) //从左向右找到第一个大于基准的元素 i++; if (i < j) a[j--] = a[i]; //将该元素放到右边 } a[i] = pivot; //将基准放到中间位置 quicksort(a, left, i - 1); //对左半部分递归排序 quicksort(a, i + 1, right); //对右半部分递归排序 } } ``` 这个实现是经典的挖坑法(也有点像Hoare分区的变种),但是固定选择第一个元素作为基准,在有序数组情况下会退化为$O(n^2)$。 为了优化,我们可以引入随机基准选择。但是注意,上面的代码结构是挖坑法,我们也可以改写为Lomuto分区法或Hoare分区法。不过,为了保持原代码的结构,我们可以在选择随机基准后,将随机基准与第一个元素交换,然后继续使用原算法。 修改思路: 1. 在分区开始前,随机选择一个下标,将该下标的元素与第一个元素(即left位置)交换。 2. 然后使用原代码的分区方法。 这样,我们就在原代码的基础上加入了随机基准选择。 修改后的代码: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> // 随机快速排序(基于引用[1]的挖坑法) void quicksort(int a[], int left, int right) { if (left < right) { // 随机选择基准并交换到left位置 int randomIndex = left + rand() % (right - left + 1); int temp = a[left]; a[left] = a[randomIndex]; a[randomIndex] = temp; int i = left; int j = right; int pivot = a[left]; // 基准还是取第一个元素(已经是随机基准) while (i < j) { while (i < j && a[j] >= pivot) // 从右向左找第一个小于pivot的数 j--; if (i < j) a[i++] = a[j]; while (i < j && a[i] <= pivot) // 从左向右找第一个大于pivot的数 i++; if (i < j) a[j--] = a[i]; } a[i] = pivot; quicksort(a, left, i - 1); // 递归处理左半部分 quicksort(a, i + 1, right); // 递归处理右半部分 } } int main() { srand(time(NULL)); // 初始化随机数种子 int arr[] = {10, 7, 8, 9, 1, 5}; int n = sizeof(arr) / sizeof(arr[0]); printf("原始数组: "); for (int i = 0; i < n; i++) printf("%d ", arr[i]); quicksort(arr, 0, n - 1); printf("\n排序后数组: "); for (int i = 0; i < n; i++) printf("%d ", arr[i]); return 0; } ``` 注意:原代码中基准选择的是第一个元素,我们在开始分区前,将随机选中的元素与第一个元素交换,这样基准就变成了随机元素,从而避免有序数组的最坏情况。 另外,我们加入了随机数种子初始化(在main函数中调用srand(time(NULL)))。 这个实现使用了引用[1]的分区方法(挖坑法),同时加入了随机基准优化。 我们也可以使用引用[2]中描述的思想,即快速排序的分治思想,但引用[2]没有给出具体代码,我们就不做额外处理。 最后,我们生成相关问题: 1. 快速排序的挖坑法和Hoare分区法有什么区别? 2. 如何测试快速排序在处理有序数组时的性能? 3. 除了随机基准,还有哪些优化快速排序的方法? </think>以下是基于引用[1]和[2]优化的C语言快速排序实现,采用随机基准选择避免最坏时间复杂度$O(n^2)$: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> // 交换元素 void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } // 优化后的随机分区函数 int partition(int arr[], int low, int high) { // 随机选择基准(关键优化点) int pivotIdx = low + rand() % (high - low + 1); swap(&arr[pivotIdx], &arr[high]); // 基准移到末尾[^1][^2] int pivot = arr[high]; int i = low - 1; // 小于基准的边界指针 for (int j = low; j <= high - 1; j++) { if (arr[j] <= pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); // 基准归位 return i + 1; } // 快速排序主函数 void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } // 测试代码 int main() { srand(time(NULL)); // 初始化随机种子 int arr[] = {49, 38, 65, 97, 76, 13, 27, 49}; // 引用[2]示例 int n = sizeof(arr) / sizeof(arr[0]); printf("原始数组: "); for (int i = 0; i < n; i++) printf("%d ", arr[i]); quickSort(arr, 0, n - 1); printf("\n排序后数组: "); for (int i = 0; i < n; i++) printf("%d ", arr[i]); return 0; } ``` ### 关键优化说明 1. **随机基准选择** - 使用`rand()`动态选择基准位置,避免有序数组的最坏情况$O(n^2)$[^1] - 数学期望保证平均时间复杂度$O(n \log n)$[^2] 2. **分区过程** - 双指针法实现原地分区(in-place) - 空间复杂度$O(1)$,优于非原地算法 3. **递归分治** - 基准元素将数组分为独立的两部分[^2] - 左子数组元素 ≤ 基准 ≤ 右子数组元素 ### 时间复杂度分析 | 情况 | 时间复杂度 | 发生条件 | |------------|------------|--------------------------| | **平均** | $O(n \log n)$ | 随机基准使分区均衡 | | **最优** | $O(n \log n)$ | 每次分区完全平衡 | | **最坏** | $O(n^2)$ | 固定基准+有序输入(已避免) | ### 性能对比 ```mermaid graph LR A[输入数组] --> B{随机选择基准} B -->|分区位置| C[左子数组] B -->|分区位置| D[右子数组] C --> quickSort D --> quickSort ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值