优质代码段

本着学好C语言的目的,写下此贴,现在发现,如果想学好编程,一些必要的算法是必须要背过的,因为这么简洁清晰的代码是普通初学者根本想不出来的。

1.scanf输入(需用回车+Ctrl+Z+回车实现完成输入)

while(scanf(“%d”,&x)==1){...}

scanf也是有返回值的,返回值为1代表成功输入了。

2.最大回文字符串(原字符串是一个整串)(此题最重要的部分就是函数的有效利用)

方法:1.清除格式(预处理,转换大小写,合理利用一些函数,可以更加简洁)->判断(中间处理)->输出

清除格式:用<ctype.h>中的几个函数:isalpha(判断大小写),isdigit(判断十进制数字),isprint(判断是否为可打印字符),toupper(返回字符大写形式),tolower(返回字符小写形式)等对每个字母依次判断。

n = strlen(buf);
m = 0;
for(i = 0; i < n; i++)
{
  if(isalpha(buf[i])) s[m++] = toupper(buf[i]);
}

然后判断出其中最大的回文串,常规操作,并没有什么窍门。

int i,j,max = 0;
for(i = 0; i < m; i++)
	for(j = i; j < m; j++)
		if(isHuiWenChuan(buf[i],buf[j]) && j-i+1 > max)
			max = j-i+1;

最后,判断回文串的函数isHuiWenChuan:

for(k = i; k < j; k++) 
    if(buf[i] != buf[j-i]) bool = 0;
其中,bool是一个判断变量,一旦两个字符不相等,那么它就会设为0代表不是回文串。

这样,就获得了最大回文串的长度,这时仍不知道它的具体位置,这时就用上了最初定义的p数组,它储存的是每一个字母在最初字符串的位置,它的下标是每一个字母在新字符串中的位置。这个处理要在之前提到的预处理中执行。总的代码如下:

#include <stdio.h>
#include <String.h>
#include <ctype.h>
#define MAXN 1000 + 10

char buff[MAXN],s[MAXN];
int p[MAXN];

int main(){
	int i,j,n,k,m = 0,bool = 1,a,b;
	scanf("%s",buff);
	n = strlen(buff);
	for(i = 0; i < n; i++)
	{
		if(isalpha(buff[i]))
		{
			p[m] = i;
			s[m++] = toupper(buff[i]);
		}
	} 	
	
	for(i = 0; i < n; i++)
	{
		for(j = i; j < n; j++)
		{
			bool=1;
			for(k = i; k <= j; k++)
			{
					if(s[k] != s[i+j-k]) bool = 0;
					if(bool && i+j-k > m) {m=i+j-1; a = p[i]; b = p[j];}
			}
		}
	}
	for(i = a; i <= b; i++)
		printf("%c",buff[i]);
	printf("\n");
}

这段代码有效率问题,运行不快,优化后的代码还恶心,这时是从中间向两边拓展,然后区分单复数,这个运行还快些。

#include <stdio.h>
#include <String.h>
#include <ctype.h>

#define MAXN 1000 + 10

char buff[MAXN],s[MAXN];
int p[MAXN];

int main(){
	int i,j,n,k,m = 0,bool = 1,a,b;
	scanf("%s",buff);
	n = strlen(buff);
	for(i = 0; i < n; i++)
	{
		if(isalpha(buff[i]))
		{
			p[m] = i;
			s[m++] = toupper(buff[i]);
		}
	} 	
	
	for(i = 0; i < n; i++)
	{
		for(j = 0; i-j >= 0 && i+j < n; j++)
               {
                    if(buff[i-j] != buff[i+j]) break;
                    if(buff[i-j] == buff[i+j] && j*2+1 > m){a = buff[i-j]; b = buff[i+j]; m = j*2+1;}
               }
               for(j = 0; i-j >=0 && i+j+1 <n;j++)
               {
                  if(buff[i-j] != buff[i+j+1]) break;
                  if(buff[i-j] == buff[i+j+1]) {a = p[i-j]; b = p[i+j+1];}
               }

	}
	for(i = a; i <= b; i++)
		printf("%c",buff[i]);
	printf("\n");
}

也可以分别单列成函数,预处理函数和处理函数,同用一个变量,耦合性比较强。

#include<stdio.h>
#include<string.h>
#include<ctype.h>                        //会用到其中的一些函数
#define MAXN 5000 + 10              //多10个保险

struct String                   //这样定义一个字符串会很方便//并不是很明智的
{
    char str[MAXN];
    int n;
};
struct String str1, str2;             //str1用来放最初字符串,str2用来放处理后的字母
int a, b;                       //标记最大回文串在原字符串中的位置
int p[MAXN];                              //用来标记str2中每个字符在str1中的位置

int function1(struct String string1,struct String string2);
void function2(struct String string);
void function3();

int main()
{
    memset(str1.str,0,sizeof(str1.str));//初始化str1
    memset(str2.str,0,sizeof(str2.str));//初始化str2
    scanf("%s",str1.str);
    str1.n = strlen(str1.str);

    str2.n = function1(str1,str2);//将str1转化为无格式的字符串,并把其放在str2中
    printf("%d",str2.n);
    printf("%s",str2.str);
    function2(str2);                //判断回文串,并求出其位置放在a,b之中
    function3();                    //输出
}

int function1(struct String string1,struct String string2)//通过判断字符是否为字母,放入str2中
{
    int a=0, b=0;
    for(a=0; a<string1.n; a++)//判断是否为字母
    {
        if(isalpha(string1.str[a]))
        {
            string2.str[b] = toupper(string1.str[a]);//强制转化为大写字母利于比较
            p[b++] = a;//记录这个字符在原字符串中的位置
        }

    }
    return strlen(string2.str);
}
void function2(struct String string)//用循环判断出回文串
{
    int i,j,k,n=0;//n代表回文串的长度
    int bool=1;//代表是不是回文串
    for(i=0; i<string.n; i++)
    {
        for(j=i; j<string.n; j++)
        {
            bool = 1;
            for(k=i; k<(i+j)/2; k++)
            {
                if(string.str[i+k] != string.str[j-k])
                    bool = 0;
            }
            if(bool==1 && j-i+1 > n)
            {
                n = j-i+1;
                a = p[i];
                b = p[j];
            }
        }
    }
}
void function3()//简单的输出
{
    int i;
    printf("最大回文串为:");
    for(i=a; i<=b; i++)
    {
        printf("%c",str1.str[i]);
    }
    printf("长度为:%d\n",a-b);
}
这段代码不对,运行不出来。

3.高精度算法

首先要定义一个结构体,其中有一个int数组和一个int变量代表其长度。

#define MAXN 1000 + 10

struct huge
{
    int a[MAXN];
    int len;
};
高精度加法:
huge jiafa(huge a, huge b)
{
	int i, L;
	huge tmp;
	L=max(a.len, b.len);
	for(i = 1; i <= L + 1; i++)
		tmp.a[i] = 0;
	for(i = 1;i <= L; i++)
	{
		tmp.a[i] += a.a[i] + b.a[i];
		tmp.a[i+1] += tmp.a[i] / 10;
		tmp.a[i] = tmp.a[i]%10; 
	}
	tmp.len = L;
	if(tmp.a[L + 1]) tmp.len++;
	return tmp;

高精度减法:

与高精度加法原理相同,最方便的记法就是背过。。

huge jianfa(huge a, huge b)
{
    int i, L;
    huge tmp;
    L=max(a.len, b.len);
    for(i = 1; i <= L + 1; i++)
        tmp.a[i] = 0;
    for(i = 1;i <= L; i++)
    {
        tmp.a[i] += a.a[i] - b.a[i];
        if(tmp.a[i] < 0)
        {
            tmp.a[i] += 10;
            a.a[i + 1]--;
        }
        tmp.len = L;
        while(!tmp.a[tmp.len])
            tmp.len--;
        return tmp;
    }
       

高精度乘法:

huge chengfa(huge a, huge b)
{
    huge c;
    int L = a.len + b.len;
    for(int i = 1;i <= L;i++)
        c.a[i] = 0;
    for(int i = 1;i < a.len; i++)
        for(int j = 1;j <=b.len; j++)
    {
        c.a[i + j -1] += a.a[i] * b.a[j];
        if(c.a[i + j -1] >= 10)
        {
            c.a[i + j] += c.a[i + j -1] / 10;
            c.[i+j-1] %= 10;
        }
    }
    c.len = L;
    while((c.len > 1) && (!c.a[c.len]))
        c.len--;
    return c;
}

高精度除法是四则运算中最难实现的一个,与平常手工运算不再完全一样,因为模拟手工算法太慢了。

高精度四则运算还可以用类的方法封装起来,重载加减乘除运算符,以便随时使用。




4.排列组合

递归实现比较简单,但开销很大,有非递归实现,但不容易理解,同时有不止一种的递归方法,有时间再更。

全排列(A)

将数组看为一个集合,将集合分为两部分:0~a和s~b,其中0~a表示已经选出来的元素,而a~b表示还没有选择的元素。

把数组分为两部分,前面0到a表示已经选出来的元素,a到b表示没有选择的元素。

#define LEN 100

int array[LEN];
void quanPaiLie(int array[], int a, int b) //b为数组长度,a从头开始。
{     
    int i;
    if(a > b)     
    {
        myPrint();//这里就开始输出
    }
    else    
    {         
        for(i = a; i <= b; i++)
        {             
             swap(array, a, i);             
             quanPaiLie(array, a + 1, b);             
             swap(array, a, i);         
        }
    }
}
void swap(int * list, int i, int j)
{
    int tmp = list[i];
    list[i] = list[j];
    list[j] = tmp;
}
void myPrint()//仅仅是一个打印函数
{
    for(int i = 0; i < LEN; i++)
    {
        printf("%d ", array[i]);
    }
    printf("\n");
}

组合(C)

每一次从集合中选出一个元素,然后对剩余的集合(n-1)进行一次k-1组合(最后只有两个元素的组合是很好想的),到最后输出。

void zuHe(int array[], int n, int k)
{
    if(k == 0)
    {
        myPrint();
        return;
    }
    for(int i = n; i >= k; i--)
    {
        subset[k-1] = array[i-1];
        if(k > 1)
        {
            zuHe(array, i-1, k-1);
        }
        else
        {
            myPrint();
        }
    }
}

排序与检索

在stdlib.h中有排序函数qsort,使用库函数排序的代码量不比冒泡排序法小,但速度却快很多。t

冒泡排序





猜你喜欢

转载自blog.csdn.net/qq_40058642/article/details/79393499