算法分析课设(五)格雷码

免责声明

本文仅为个人学习笔记,请谨慎参考,如有错误欢迎批评指正。

要求

格雷码是具有如下特点的编码,当输入n为如下数时对应的格雷码:

n=1: 0, 1

n=2: 00, 01, 11,10

n=3: 000,001,011,010, 110,111,101,100

格雷码要求相邻两个格雷码之间只有一位不同,其他位均相同。要求:

(1)写出n=5时的格雷码,要求写出求解过程中变量的变化过程以及求解结果。

(2)写出算法分析过程,试编写程序求输入n时对应的格雷码,并分析算法的时间复杂度。

参考链接

https://leetcode-cn.com/problems/gray-code/comments/

https://leetcode-cn.com/problems/gray-code/solution/chun-cdi-gui-fa-qiu-jie-89ge-lei-bian-ma-si-lu-qin/

第一个题解,用的公式法是最简单的。

第二个题解,本文代码是基于它改的。

分析

这里我选择递归的方法来理解。

首先我们还是要找出格雷码的规律:

要看完整代码拉到最后,下面展示写代码的思路。

对于递归函数的构造,主要包括结束条件、递归调用和数据处理,三者顺序不限。因为我们要先构造n=0,n=1,n=2......我们就要先递归,再对数据进行处理。所以递归函数的大致结构是这样的。

void getGray(gray_arr, n){
	// 1.结束条件
	if(n==0){
		gray_arr[n]=0;
		return 1;
	}

	// 2.递归调用
	getGray(gray_arr, n-1);

	// 3.数据处理
	for(int i=0; i<gray_arr的长度; i++){
		// 复制n-1的格雷码,在每个后面添加1或0
	}
}

C中函数将数组gray_arr作为传入参数的话,学过指针都知道,是会永久改变gray_arr数组的。C中没有直接返回数组长度的函数,所以该函数最好返回经复制后的数组长度,不然用pow自己算。

int getGray(gray_arr, n){
	// 1.结束条件
	if(n==0){
		gray_arr[n]=0;
		return 1;
	}

	// 2.递归调用
	int length = getGray(gray_arr, n-1);

	// 3.数据处理
	for(int i=0; i<length; i++){
		// 复制n-1的格雷码,在每个后面添加1或0
	}

    return length*2;
}

大致的结构有了,开始写数据处理部分:

int getGray(int gray_arr[], int n){
	// 1.结束条件
	if(n==0){
		gray_arr[n]=0;
		return 1;
	}

	// 2.递归调用
	// 头可能会晕,但是就记住,假如n=3那么经过这个递归我们已经获得了n=2的格雷码数组和它的长度
	int length = getGray(gray_arr, n-1);

	// 3.数据处理
	// 在n-1格雷码数组的基础上填写n的格雷码,即复制n-1的格雷码,分别在末位添加0或1
	// 注意,gray_arr数组是从1开始的,不是0,length指向的就是最后一个数
	for(int i = length-1; i >= 0; i--)
    {
    	// 这里举具体的例子G(2)和G(3)方便理解
    	// G(2)={00,     01,     11,     10}
    	// G(3)={000,001,011,010,110,111,101,100}
    	// 每次循环i分别指向G(2)的4个数
    	// 我们要从G(3)的最后一个位置开始填写,不然会把后面的数覆盖了
    	// 这也是为什么i要从length开始

    	// i=0时,末位添加0、1;
    	// i=1时,末位添加1、0;
    	// i=2时,末位添加0、1。。。
    	// 所以i为偶数是0、1;i为偶数是1、0
    	int a,b;
    	i%2==0?(a=0,b=1):(a=1,b=0);
    	// i*2和i*2-1就是一对G(2)到G(3)复制出来的数
		gray_arr[i*2]   = gray_arr[i]*10+a;
    	gray_arr[i*2+1] = gray_arr[i]*10+b;
        
    }

    return length*2;
}

完整代码如下: 

#include <stdio.h>
#include <math.h>

int getGray(int gray_arr[], int n){
	// 1.结束条件
	if(n==0){
		gray_arr[n]=0;
		return 1;
	}

	// 2.递归调用
	// 头可能会晕,但是就记住,假如n=3那么经过这个递归我们已经获得了n=2的格雷码数组和它的长度
	int length = getGray(gray_arr, n-1);

	// 3.数据处理
	// 在n-1格雷码数组的基础上填写n的格雷码,即复制n-1的格雷码,分别在末位添加0或1
	// 注意,gray_arr数组是从1开始的,不是0,length指向的就是最后一个数
	for(int i = length-1; i >= 0; i--)
    {
    	// 这里举具体的例子G(2)和G(3)方便理解
    	// G(2)={00,     01,     11,     10}
    	// G(3)={000,001,011,010,110,111,101,100}
    	// 每次循环i分别指向G(2)的4个数
    	// 我们要从G(3)的最后一个位置开始填写,不然会把后面的数覆盖了
    	// 这也是为什么i要从length开始

    	// i=0时,末位添加0、1;
    	// i=1时,末位添加1、0;
    	// i=2时,末位添加0、1。。。
    	// 所以i为偶数是0、1;i为偶数是1、0
    	int a,b;
    	i%2==0?(a=0,b=1):(a=1,b=0);
    	// i*2和i*2-1就是一对G(2)到G(3)复制出来的数
		gray_arr[i*2]   = gray_arr[i]*10+a;
    	gray_arr[i*2+1] = gray_arr[i]*10+b;
        
    }

    return length*2;
}

int main(){
	int n;
	scanf("%d",&n);
	int num = (int)pow(2,n);
	int gray_arr[num];
	// 返回格雷码
	getGray(gray_arr, n);
	// 打印格雷码
	for(int i=0;i<num;i++){
		// 这样打印前面的0不会显示,时间紧迫就不搞了
		printf("%d ", gray_arr[i]);
	}
	return 0;
}

算法的复杂度是 O(2^{N}),应该吧。。。

猜你喜欢

转载自blog.csdn.net/qq_33514421/article/details/112426028
今日推荐