c语言学习之代码

这篇博客深入探讨了C语言中的编程实践,涵盖了贪心算法、哈弗曼编码、八皇后问题、括号匹配、链表操作(双向链表与单向循环链表)、万年历实现、约瑟夫环问题以及递归和逆波兰表达式的求解。通过这些实例,读者可以提升对C语言及基础算法的理解。
摘要由CSDN通过智能技术生成

1、贪心算法

//贪心算法装箱问题
#include<stdio.h>
#include<stdlib.h>
#define V 100



//物品体积
typedef struct
{
	int gno;//物品编号
	int gv;//物品体积
}ELE;

//物品结点
typedef struct goods
{
	int vno;
	struct goods * link;
}GOODS;

//箱子结点
typedef struct box
{
	int remainder;//剩余体积
	GOODS * hg;
	struct box * next;
}BOX;

void printELE(ELE * head,int n)
{
	int i;
	for(i=0;i<n;i++)
		printf("%d,%d\n",head[i].gno,head[i].gv);
}

void printBOX(BOX * head)
{
	BOX * p=head;
	int i=1;
	while(p)
	{
		printf("\n第%d个箱子剩余%d\t",i++,p->remainder);
		while(p->hg)
		{
			printf("这个箱子装了%d\t",p->hg->vno);
			p->hg=p->hg->link;
		}
		p=p->next;
	}
}

//降序排序
void sortD(ELE * g,int n)
{
	int i;
	int j;
	ELE t;
	for(i=0;i<n-1;i++)
		for(j=0;j<n-i;j++)
			if(g[j].gv<g[j+1].gv)
			{
				t=g[j];
				g[j]=g[j+1];
				g[j+1]=t;
			}
}

//装箱
BOX * process(ELE * g,int n)
{
	int i;
	BOX * h=NULL,* t,* p,* k;
	GOODS * q,* m;
	for(i=0;i<n;i++)
	{
		q=(GOODS *)malloc(sizeof(GOODS));//先给物品分配
		q->vno=g[i].gno;
		q->link=NULL;
		for(k=h;k&&k->remainder<g[i].gv;k=k->next);//没开箱子的情况,即K为NULL,或者找出能放下的第一个箱子
		if(!k)//这里是一个箱子都没开
		{
			p=(BOX *)malloc(sizeof(BOX));//开箱
			p->remainder=V;
			p->next=NULL;
			if(!h)//是不是第一个箱子
				h=t=p;
			else
				t=t->next=p;//不是直接挂,t指向最后一个箱子
			t->next=NULL;
			p->hg=q;
			p->remainder=V-g[i].gv;//放入物品
		}
		else//这个是有箱子,并且能放下
		{
			for(m=k->hg;m->link;m=m->link);
			m->link=q;
			k->remainder-=g[i].gv;
		}
	}
	return h;
}

int main(void)
{
	ELE * g=NULL;
	BOX * b=NULL;
	int i;
	int n;
	printf("请输入物品个数:\n");
	scanf("%d",&n);
	g=(ELE *)malloc(n*sizeof(ELE));
	//输入物品数据
	for(i=0;i<n;i++)
	{
		g[i].gno=i+1;
		printf("请输入第%d个物品的体积:",i+1);
		scanf("%d",&g[i].gv);
	}
	printELE(g,n);
	sortD(g,n);
	printELE(g,n);
	b=process(g,n);
	printBOX(b);
}

2、哈弗曼编码

//哈夫曼编码,利用结构体数组存储哈夫曼树
//用另一个结构体存储编码

#include<stdio.h>
#include<stdlib.h>

#define N 10

typedef struct
{
	char word;//存储字符
	int weight;
	int left,right,parent;
}HuffNode;

typedef struct
{
	int code[N];
	int start;
}HuffCode;

void CreatHuffManTree(HuffNode * hn,int n)
{
	int i;
	int j;
	int k1;
	int k2;
	for(i=0;i<n-1;i++)
	{
		k1=k2=-1;
		for(j=0;j<n+i;j++)
		{
			if(hn[j].parent==-1&&k1==-1)
				k1=j;
			else if(hn[j].parent==-1)
			{
				k2=j;
				break;
			}
			for(;j<n+i;j++)
				if(hn[j].parent==-1)
					if(hn[j].weight<hn[k1].weight)
					{
						k2=k1;k1=j;
					}
					else if(hn[j].weight<hn[k2].weight)
						k2=j;
			hn[n+i].weight=hn[k1].weight+hn[k2].weight;
			hn[n+i].parent=-1;
			hn[n+i].left=k1;
			hn[n+i].right=k2;
			hn[k1].parent=hn[k2].parent=n+i;
		}
	}
}

void CreatHuffManCode(HuffNode * hn,int n,HuffCode * hc)
{
	int i;
	int c;
	int p;
	for(i=0;i<n;i++)
	{
		c=i;
		p=hn[c].parent;
		hc[i].start=N;
		while(p!=-1)
		{
			if(hn[p].left==c)
				hc[i].code[--hc[i].start]=0;
			else
				hc[i].code[--hc[i].start]=1;
			c=p;
			p=hn[c].parent;
		}
	}
}

void printHuffManCode(HuffNode * hn,int n,HuffCode * hc)
{
	int i;
	int j;
	for(i=0;i<n;i++)
	{
		printf("%c的编码是:",hn[i].word);
		for(j=hc[i].start;j<N;j++)
			printf("%2d",hc[i].code[j]);
		printf("\n");
	}
}

int main(void)
{
	int i;
	char c;
	int w;
	int leafcount;
	HuffNode * hn;
	HuffCode * hc;
	printf("请输入叶子个数:");
	scanf("%d",&leafcount);
	hn=(HuffNode *)malloc((2*leafcount-1)*sizeof(HuffNode));
	for(i=0;i<leafcount;i++)
	{
		printf("请输入第%d个叶子的信息:\n权值 字符 ",i+1);
		scanf("%d %c",&w,&c);//先输字符回车被误判
		//printf("权值:");
		//scanf("%d",&w);
		hn[i].word=c;
		hn[i].weight=w;
		hn[i].left=hn[i].right=hn[i].parent=-1;
	}
	CreatHuffManTree(hn,leafcount);
	hc=(HuffCode *)malloc(leafcount*sizeof(HuffCode));
	CreatHuffManCode(hn,leafcount,hc);
	printHuffManCode(hn,leafcount,hc);

}

3、八皇后

//八皇后

#include<stdio.h>

int a[8]={0};	//存储第几列能不能放皇后
int b[15]={0};	//存储左上右下方向能不能放皇后
int c[15]={0};	//存储左下右上方向能不能放皇后
int x[8]={0};	//存储第几行的皇后放在第几个

void print(void)
{
	int i;
	int j;
	for(i=0;i<8;i++)
	{
		for(j=0;j<8;j++)
		{
			if(x[i]==j)
				printf("Q");
			else
				printf("*");
		}
		printf("\n");
	}
}

void chess(int i)
{
	int j;
	for(j=0;j<8;j++)
	{
		if(a[j]==0 && b[i+j]==0 && c[i-j+7]==0)
		{
			a[j]=b[i+j]=c[i-j+7]=1;
			x[i]=j;
			if(i<7)
				chess(i+1);
			else
			{
				print();
				printf("\n");
			}
			a[j]=b[i+j]=c[i-j+7]=0;
			x[i]=0;
		}
	}
}

int main(void)
{
	chess(0);
	return 0;
}

4、判断左右括号匹配

//判断一个表达式的左右括号数目是否匹配
#include<stdio.h>
#include<string.h>

void main(void)
{
	char exp[100];
	int top=-1,i;
	printf("请输入一个表达式:\n");
	gets(exp);
	for(i=0;exp[i]!=0;i++)
	{
		if(exp[i]=='(')
			top++;
		else if(exp[i]==')')
			if(top>=0)
				top--;
			else
			{
				top--;
				break;
			}
	}
	if(top==-1)
		printf("匹配!");
	else
		printf("不匹配!");
}

5、双向链表

//2013_2_26不带头结点的双向链表

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>

typedef struct node
{
	int data;
	struct node *pp,*fp;
}ElemPSN;

//创建双向链表
ElemPSN *CreateDlink(int a[],int n)
{
	ElemPSN *head,*tail,*p;
	int i;
	//head是头结点指针,tail作为尾指针
	head=tail=p=NULL;
	for(i=0;i<n;++i)
	{
		p=(ElemPSN *)malloc(sizeof(ElemPSN));
		p->data=a[i];
		p->pp=p->fp=NULL;
		if(i==0)
			//判断是否为第一个结点
			head=tail=p;
		else
		{
			tail->pp=p;
			p->fp=tail;
			tail=p;
		}
	}
	return head;
}

//正向输出该链表的数据域的值
void Aprintlink(ElemPSN *head)
{
	ElemPSN *p;
	for(p=head;p;p=p->pp)
		printf("%5d",p->data);
}

//逆向输出该链表的数据域的值
void Bprintlink(ElemPSN *head)
{
	ElemPSN *p;
	for(p=head;p->pp;p=p->pp);
	//两个for循环的终止条件不同
	for(;p;p=p->fp)
		printf("%5d",p->data);
}

//删除双向链表中值为val的结点
//假设没有重复值
//不需要两个指针联动,分头删、尾删、中间删
ElemPSN *DelNode(ElemPSN *head,int val)
//需要有返回值,否则有可能删掉head
{
	ElemPSN *p,*q,*s;
	//s,q分别作为p的前驱结点和后继结点
	for(p=head;p&&p->data!=val;p=p->pp);
	//寻找值为val的结点
	if(!p)
		printf("没有找到值为val的结点。\n");
	else
	{
		q=p->pp;
		s=p->fp;
		if(p==head)
		//分为三种情况
		{
			q->fp=s;
			head=q;
		}
		else if(p->pp==NULL)
			s->pp=q;
		else
		{
			s->pp=q;
			q->fp=s;
		}
		free(p);
	}
	return head;
}

//主函数
int main(void)
{
	int a[]={10,20,30,40,50};
	int val;
	ElemPSN *head,*p;
	//创建双向链表
	head=CreateDlink(a,5);
	//正向输出
	Aprintlink(head);
	printf("\n");
	//逆向输出
	Bprintlink(head);
	printf("\n");
	//删除值为val的结点
	printf("请输入要删的值val:");
	scanf("%d",&val);
	head=DelNode(head,val);
	//正向输出
	Aprintlink(head);
	printf("\n");
}

6、单向循环链表

//创建单向循环链表以及实现插入和删除

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>

typedef struct Node
{
	int data;
	struct Node *next;
}ElemSN;

//单向循环链标的创建
ElemSN * CreateLink(int a[],int n)
{
	ElemSN * head, * p,* tail;
	int i;
	for(i=0;i<n;++i)
	{
		p=(ElemSN *)malloc(sizeof(ElemSN));
		p->data=a[i];
		if(i==0)
			head=tail=p;
		else
			tail=tail->next=p;
		tail->next=head;
	}
	return head;
}

//输出单项循环链表
PrintLink(ElemSN * head)
{
	ElemSN * p=head;
	printf("单向循环链表的值为:\n");
	do
	{
		printf("%5d",p->data);
		p=p->next;
	}while(p!=head);
}

//删除值为val的结点,假设无重复值
ElemSN * DelNode(ElemSN * head,int val)
{
	ElemSN * p=head,* q=NULL;
	do
	{
		if(p->data==val)
			break;
		q=p;
		p=p->next;
	}while(p-head);//也可以以q作为判断条件

/*可替换if为下
	if(p==head&&q!=NULL)
		printf("没有找到要删除的值!\n");
	else
	{
		if(q==NULL)
		{
			for(q=p;q->next!=head;q=q->next);
			head=p->next;	
		}
		q->next=p->next;
		free(p);
	}
*/
	if(p!=head)
	{
		q->next=p->next;
		free(p);
	}
	else if(q==NULL)
	{
		for(q=p;q->next!=head;q=q->next);
		q->next=p->next;
		head=p->next;
		free(p);
	}
	else
		printf("没有找到要删除的值!\n");
	return head;
}

//插入新结点s,假设有序
ElemSN * InsertNode(ElemSN * head,ElemSN * s)
{
	ElemSN * p=head,* q=NULL;
	do
	{
		if(p->data>s->data)
			break;
		q=p;
		p=p->next;
	}while(p-head);
	if(q==NULL)
	{
		for(q=p;q->next!=p;q=q->next);
		head=s;
	}
	s->next=p;
	q->next=s;
	return head;
}

//主函数
int main(void)
{
	ElemSN * head,* s;
	ElemSN x;
	int a[6]={10,20,30,40,50,60};
	int val,insert;
	head=CreateLink(a,6);
	PrintLink(head);
	printf("\n");
	printf("请输入要删除的值:\n");
	scanf("%d",&val);
	head=DelNode(head,val);
	PrintLink(head);
	printf("\n");
	printf("请输入要插入的值:\n");
	scanf("%d",&insert);
	s=(ElemSN *)malloc(sizeof(ElemSN));
	s->data=insert;
	//s=&x;
	//x.data=insert;
	head=InsertNode(head,s);
	PrintLink(head);
	printf("\n");
}

7、万年历

//已知1900年1月1号是礼拜一,任意输入年月,打印出该月的日历

#include<stdio.h>

void main(void)
{
	int i=1900,sum=1,k;//sum最终表示这月第一天是星期几,k表示这月有几天
	int year,month;
	printf("请输入大于1900年的年份:\n");
		scanf("%d",&year);
	printf("请输入月份:\n");
		scanf("%d",&month);
	for(;i<year;i++)
	{
		if((i%4==0&&i%100!=0)||i%400==0)//判断是润年
			sum+=366;
		else
			sum+=365;
	}
	switch(month)
	{
		case 12 :sum+=30;
		case 11 :sum+=31;
		case 10 :sum+=30;
		case 9 :sum+=31;
		case 8 :sum+=31;
		case 7 :sum+=30;
		case 6 :sum+=31;
		case 5 :sum+=30;
		case 4 :sum+=31;
		case 3 :			
			if((i%4==0&&i%100!=0)||i%400==0)//判断是润年
				sum+=29;
			else	
				sum+=28;
		case 2 :sum+=31;
	}	
	sum=(sum-1)%7+1;//+1算出这月第一天是礼拜几,第一列从礼拜天开始,因此第一天是礼拜几,就得打几次tab
	printf("\n\t\t\t\t%d年%d月\t\t\t\t\n\n",year,month);
	printf("\t日\t一\t二\t三\t四\t五\t六\t\n");
	if(sum!=7)
		for(i=0;i<sum;i++)
			printf("\t");
	if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)
		k=31;
	else if(month==2)
	{
		if((i%4==0&&i%100!=0)||i%400==0)//判断是润年
				k=29;
			else	
				k=28;
	}
		else
			k=30;
	for(i=1;i<=k;i++)
	{
		printf("\t%d",i);
		if((sum+i)%7==0)
			printf("\n\n");		
	}
	printf("\n");
}

8、约瑟夫环

#include<stdio.h>
#define N 100
void main()
{
	int a[N],m,n,k=0,j,i;
	printf("请输入人数n:\n");
	scanf("%d",&n);
	printf("请输入正整数m:\n");
	scanf("%d",&m);
	printf("请输入各个人的密码:\n");
	for(i=0;i<n;i++)
	scanf("%d",&a[i]);
	printf("出列顺序为:");
	for(i=0;i<n;i++)
	{
		j=1;
		while(j<m)
		{
			while(a[k]==0)
				k=(k+1)%n;
			j++;
			k=(k+1)%n;
		}

		while(a[k]==0)
			k=(k+1)%n;
		printf("%4d",k+1);
		m=a[k];
		a[k]=0;
	}
}

9、递归

//一些简单的递归的调用

#include<stdio.h>

int jiecheng1(int n)
{
	int m=1;
	n&&(m=n*jiecheng1(n-1));
	return m;
}

int jiecheng2(int n)
{
	if(n==0)
		return 1;
	else
		return n*jiecheng2(n-1);
}

void erjinzhi1(int n)
{
	if(n!=0)
		erjinzhi1(n/2);
	printf("%2d",n%2);
}

int lianjia(int n)
{
	int m=0;
	n&&(m=n+lianjia(n-1));
	return m;
}


void nizhi(int n)
{
	if(n!=0)
	{
		printf("%2d",n%10);
		n=n/10;
		nizhi(n);
	}
}

int weihe(int n)
{
	int m=0;
	if(n!=0)
		m=n%10+weihe(n/10);
	return m;
}

int weimax(int n)
{
	int m=0;
	if(n!=0)
	{
		m=((m<=(n%10)?(n%10):weimax(n/10)));
	}
	return m;
}

int weishu(int n)
{
	int m=0;
	if(n!=0)
		m=weishu(n/10)+1;
	return m;
}

void print(int a[],int n)
{
	if(n!=0)
	{
		printf("%5d",a[0]);
		print(a+1,n-1);
	}
}


void fanprint(int a[],int n)
{
	if(n!=0)
	{
		fanprint(a+1,n-1);
		printf("%5d",a[0]);
		
	}
}

int arraysum(int a[],int n)
{
	if(n==1)
		return a[0];
	else
		return a[0]+arraysum(a+1,n-1);
}

void main(void)
{
	int n=4;
	int m=543210;
	int a[10]={1,2,3,4,5,6,7,8,9,0};
	printf("%d的阶乘是%d,%d!\n",n,jiecheng1(n),jiecheng2(n));
	printf("%d的二进制是:",n);
	erjinzhi1(n);
	printf("\n%d的连加是%d!\n",n,lianjia(n));
	printf("%d的逆置是:",m);
	nizhi(m);
	printf("\n%d的各个位之和是:%d\n",m,weihe(m));	
	printf("%d的位数是:%d\n",m,weishu(m));
	printf("数组a的正向逆向输出是:\n");
	print(a,10);
	printf("\n");
	fanprint(a,10);
	printf("\n数组a的和是:%d\n",arraysum(a,10));
}

10、逆波兰表达式

//逆波兰表达式实现表达式的计算
#include<stdio.h>
#include<string.h>

int opl(char ch) //运算符的优先级判断
{
	int op;
	switch (ch)
	{
	case '*' :
	case '/' : op=4;break;
	case '+' :
	case '-' : op=3;break;
	case '(' : op=2;break;
	case '@' : op=1;
	}
	return op;
}

long process(long x1,long x2,char ch) //将字符运算符应用成算术运算符
{
	long op;
	switch (ch)
	{
	case '*' : op=x2*x1;break;
	case '/' : op=x2/x1;break;
	case '+' : op=x2+x1;break; 
	case '-' : op=x2-x1;break;
	}
	return op;
}

void exchange(char pm[],char pa[]) //将中缀表达式转化为后缀表达式(逆波兰表达式)
{
	char stack[10];
	int top=-1;
	stack[++top]='@';
	while(*pm)
	{
		if(*pm=='(')
		{
			stack[++top]='(';
			pm++;
		}
		else if(*pm>='0'&&*pm<='9')
		{
			(*pa)=(*pm);
			pm++;
			pa++;
		}
		else if(*pm=='+'||*pm=='-'||*pm=='*'||*pm=='/')
		{
			while(opl(*pm)<=opl(stack[top]))//栈外运算符优先级>栈顶运算符优先级,直接入
											//反之,<=则先出,出完再入
				*(pa++)=stack[top--];
			
			stack[++top]=*(pm++);
			*(pa++)=' ';
		}
		else if(*pm==')')
		{
			while(stack[top]!='(')
				*(pa++)=stack[top--];
			top--;
			pm++;
		}
		else
			pm++;
	}
	while(stack[top]!='@')
	{
		*(pa++)=stack[top--];
	}
	*pa=0; //给pa一个结束标志,注意不是赋值'0'
}

long complete(char a[])//对后缀表达式进行计算
{
	long x1,x2,y,top=-1;
	long stack[30];
	while(*a)
	{
		if(*a==' ')
			a++;
		else if(*a>='0'&&*a<='9')
		{
			y=0;
			while(*a>='0'&&*a<='9')
			{
				y=y*10+*a-'0'; //将字符转化为数字
				a++;
			}
			stack[++top]=y;
		}
		else if(*a=='+'||*a=='-'||*a=='*'||*a=='/')
		{
			x1=stack[top--];
			x2=stack[top--]; // 注意区分x1,x2的顺序
			stack[++top]=process(x1,x2,*a);
			a++;
		}
	}
	if(top==0)
		return stack[top];
	else
		return 0;
}

//判断括号匹配
int pipei(char exp[])
{
	int i,top=-1;
	for(i=0;exp[i]!=0;i++)
	{
		if(exp[i]=='(')
			top++;
		else if(exp[i]==')')
			if(top>=0)
				top--;
			else
			{
				top--;
				break;
			}
	}
	if(top==-1)
		return 1;
	else
		return 0;
}

//主函数
void main(void)
{
	char m[100],a[100];
	long record=0;
	printf("请输入一个表达式:\n");
	gets(m);
	if(pipei(m))
	{
		exchange(m,a);
		printf("后缀表达式为:%s!\n",a);
		record=complete(a);
		printf("这个表达式的值是%ld!\n",record);
	}
	else
		printf("左右括号不匹配,无法计算!\n");
}









评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值