例题1:
//通过键盘输入一组多项式的系数和指数,用尾插法建立一元多项式的链表。
//以输入系数为0为结束标志,并约定建立多项式链表时,总是按指数从小到大的顺序排列
#include<stdio.h>
#include<stdlib.h>
typedef struct Polynode
{
int coef;
int exp;
struct Polynode *next;
}Polynode,*PolyList;
void input(PolyList LA);
PolyList PolyAdd(PolyList LA,PolyList LB);
void output(PolyList LC);
int main()
{
PolyList LA,LB,LC;
LA=(PolyList)malloc(sizeof(Polynode));
LB=(PolyList)malloc(sizeof(Polynode));
input(LA);
input(LB);
LC=PolyAdd(LA,LB);
output(LC);
return 0;
}
void input(PolyList LA)
{
Polynode *tail,*s;
int c,e;
tail=LA;
scanf("%d %d",&c,&e);
while(c){
s=(Polynode *)malloc(sizeof(Polynode));
if(s!=NULL){
s->coef=c;
s->exp=e;
tail->next=s;
tail=s;
scanf("%d %d",&c,&e);
}
}
tail->next=NULL;
}
PolyList PolyAdd(PolyList LA,PolyList LB)
{
Polynode *p,*q,*tail,*temp;
int sum;
p=LA->next;
q=LB->next;
tail=LA;
while(p!=NULL&&q!=NULL){
if(p->exp<q->exp){
tail->next=p;
tail=p;
p=p->next;
}
else if(p->exp==q->exp){
sum=p->coef+q->coef;
if(sum!=0){
p->coef=sum;
tail->next=p;
tail=p;
p=p->next;
temp=q;
q=q->next;
free(temp);
}
else{
temp=p;
p=p->next;
free(temp);
temp=q;
q=q->next;
free(temp);
}
}
else{
tail->next=q;
tail=q;
q=q->next;
}
}
if(p){
tail->next=p;
}
else{
tail->next=q;
}
free(LB);
return LA;
}
void output(PolyList LC)
{
Polynode *p;
p=LC->next;
while(p!=NULL){
printf("%d %d\n",p->coef,p->exp);
p=p->next;
}
}
核心部分:
一元多项式的相加运算中分为三种情况:
(1) p->exp < q->exp;
(2) p->exp==q->exp;
(3)p->exp > q->exp;
写代码中注意使用malloc函数时可以另外再申请一个指针变量指向其所申请的空间地址;另外注意使用PolyList和Polynode *定义指针时候的区别。
例题2:括号匹配问题(利用栈的特点)
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1;
#define FALSE 0;
typedef struct node
{
char a;
struct node *next;
}StackNode,*LinkNode;
void bracketmatch(char *str);
void InitStack(LinkNode *S);
void push(char str,LinkNode S);
int IsEmpty(LinkNode S);
int Match(char str,LinkNode S);
void pop(LinkNode S);
int main()
{
char str[100];
scanf("%s",str);
bracketmatch(str);
return 0;
}
void bracketmatch(char *str)
{
LinkNode S;
int i;
InitStack(&S);
for(i=0;str[i]!='\0';i++){
switch(str[i])
{
case '(':
case '[':
case '{':
{
push(str[i],S);
break;
}
case ')':
case ']':
case '}':
{
if(IsEmpty(S)){
printf("右括号多余!\n");
return;
}
else{
if(Match(str[i],S))pop(S);
else{
printf("括号不匹配!\n");
return;
}
}
break;
}
default :
{
printf("输入错误!");
return;
}
}
}
if(IsEmpty)printf("括号匹配!\n");
else printf("左括号多余!\n");
}
void InitStack(LinkNode *S)
{
*S=(LinkNode)malloc(sizeof(StackNode));
(*S)->next=NULL;
}
void push(char str,LinkNode S)
{
StackNode *p;
p=(StackNode *)malloc(sizeof(StackNode));
if(p!=NULL){
p->a=str;
p->next=S->next;
S->next=p;
}
}
int IsEmpty(LinkNode S)
{
if(S->next==NULL){
return TRUE;
}
else return FALSE;
}
int Match(char str,LinkNode S)
{
switch(str)
{
case '(':
{
if(S->next->a==')')
{
return TRUE;
}
else return FALSE;
}
case '[':
{
if(S->next->a==']')
{
return TRUE;
}
else return FALSE;
}
case '{':
{
if(S->next->a=='}')
{
return TRUE;
}
else return FALSE;
}
}
}
void pop(LinkNode S)
{
StackNode *temp;
temp=S->next;
S->next=temp->next;
free(temp);
}
注意:
(1)链表和栈的初始化中,是(S)->next=NULL;而不是S->next=NULL;
(2)
if(S->next->a==']') return TRUE;
else return FALSE;
此代码编译器会报错“else没有相应的if与之匹配!”,而应改写成:
if(S->next->a==']'){
return TRUE;
}
else return FALSE;
例题3:无括号算数运算(+、-、*、/)
#include<stdio.h>
#include<stdlib.h>
typedef struct ovsnode
{
int num;
struct ovsnode *next;
}OvsNode,*LinkOvsNode;
typedef struct optrnode
{
char a;
struct optrnode *next;
}OptrNode,*LinkOptrNode;
int operation2(char *str);
void InitStack1(LinkOvsNode *A);
void InitStack2(LinkOptrNode *B);
void push1(int y,LinkOvsNode A);
void push2(char y,LinkOptrNode B);
void pop1(int *a,LinkOvsNode A);
void pop2(char *m,LinkOptrNode B);
int gettop(LinkOvsNode A);
int operation(int a,char m,int b);
char campare(char str,LinkOptrNode B);
int main()
{
char str[100];
int n;
scanf("%s",str);
n=operation2(str);
printf("%d",n);
return 0;
}
int operation2(char *str)
{
int i,y;
int a,b,c;
int n;
char x,m;
LinkOvsNode A;
LinkOptrNode B;
OptrNode *p;
InitStack1(&A);
InitStack2(&B);
//int g=0;
for(i=0;str[i]!='\0';i++){
x=str[i];
if(x>='0'&&x<='9')
{//数字
y=x-48;
// printf("%d\n",y);
push1(y,A);
}
else{
if(B->next!=NULL)
{
switch(campare(str[i],B))
{
case '>':
{
push2(str[i],B);
// printf("%c",B->next->a);
break;
}
case '=':
case '<':
{
pop1(&a,A);
pop1(&b,A);
pop2(&m,B);
c=operation(a,m,b);
push1(c,A);
push2(str[i],B);
break;
}
}
}
else
{
push2(str[i],B);
}
}
}
p=B;
// int k=0;
// printf("%c",p->a);
while(p->next!=NULL){
// k++;
// printf("%d\n",k);
pop1(&a,A);
// printf("%d\n",a);
pop1(&b,A);
// printf("%d\n",a);
pop2(&m,B);
// printf("%c\n",m);
c=operation(a,m,b);
// printf("%d\n",c);
push1(c,A);
}
// if(p==NULL)printf("p is NULL");
n=A->next->num;
free(A);
free(B);
return n;
}
void InitStack1(LinkOvsNode *A)
{
*A=(LinkOvsNode)malloc(sizeof(OvsNode));
(*A)->next=NULL;
}
void InitStack2(LinkOptrNode *B)
{
*B=(LinkOptrNode)malloc(sizeof(OptrNode));
(*B)->next=NULL;
}
void push1(int y,LinkOvsNode A)
{
OvsNode *p;
p=(OvsNode*)malloc(sizeof(OvsNode));
if(p!=NULL){
p->num=y;
p->next=A->next;
A->next=p;
// printf("%d\n",A->next->num);
}
}
void push2(char y,LinkOptrNode B)
{
OptrNode *p;
p=(OptrNode*)malloc(sizeof(OptrNode));
if(p!=NULL){
p->a=y;
p->next=B->next;
B->next=p;
// printf("%c",B->next->a);
}
}
void pop1(int *a,LinkOvsNode A)
{
OvsNode *temp;
temp=A->next;
*a=temp->num;
// printf("%d\n",*a);
A->next=temp->next;
free(temp);
}
void pop2(char *m,LinkOptrNode B)
{
OptrNode *temp;
temp=B->next;
*m=temp->a;
B->next=temp->next;
free(temp);
}
int operation(int a,char m,int b)
{
int c;
switch(m)
{
case '+':c=a+b;break;
case '-':c=a-b;break;
case '*':c=a*b;break;
case '/':c=a/b;break;
}
return c;
}
char campare(char str,LinkOptrNode B)
{
char s;
s=B->next->a;
// printf("%c",s);
switch(str)
{
case '+':
{
switch(s)
{
case '+':
case '-':return '=';break;
case '*':
case '/':return '<';break;
}
break;
}
case '-':
{
switch(s)
{
case '+':
case '-':return '=';break;
case '*':
case '/':return '<';break;
}
break;
}
case '*':
{
switch(s)
{
case '+':
case '-':return '>';break;
case '*':
case '/':return '=';break;
}
break;
}
case '/':
{
switch(s)
{
case '+':
case '-':return '>';break;
case '*':
case '/':return '=';break;
}
}
}
}
注意:下面的代码中,注意在while循环中不能再使用p=p->next;来作为循环的控制语句。由于在while循环中调用了pop(出栈)函数,而出栈函数也就相当于隐式地释放了之前申请的内存空间,若继续使用p=p->next这样的控制语句,就会使得p指针变为迷途指针,使程序出现问题。所以只要有p->next!=NULL这个语句就欧克了。(这其中也体现了栈的后进先出的特点以及头插法建立链表的特点)
p=B;
// int k=0;
// printf("%c",p->a);
while(p->next!=NULL){
// k++;
// printf("%d\n",k);
pop1(&a,A);
// printf("%d\n",a);
pop1(&b,A);
// printf("%d\n",a);
pop2(&m,B);
// printf("%c\n",m);
c=operation(a,m,b);
// printf("%d\n",c);
push1(c,A);
}
例题四:打印杨辉三角前n行元素
//打印杨辉三角前n行元素
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
typedef struct
{
int a[MAXSIZE];
int front;
int rear;
}SeqQueue;
void InitQueue(SeqQueue *Q);
void PrintYhsj(SeqQueue *Q,int n);
int main()
{
int n;
SeqQueue *Q;
Q=(SeqQueue*)malloc(sizeof(SeqQueue));
scanf("%d",&n);
InitQueue(Q);
PrintYhsj(Q,n);
return 0;
}
void InitQueue(SeqQueue *Q)
{
Q->front=Q->rear=0;
}
void PrintYhsj(SeqQueue *Q,int n)
{
int i,j,k,m;
int flag=0;
for(j=1;j<=n-1;j++)printf(" ");
printf("1\n");
if(n>=2){
Q->a[Q->rear]=1;
Q->rear=(Q->rear+1)%MAXSIZE;
Q->a[Q->rear]=1;
Q->rear=(Q->rear+1)%MAXSIZE;
for(k=2;k<=n;k++){//n行
for(m=1;m<=n-k;m++)printf(" ");//前面空格
if(n==2){
flag=1;
printf("1 1\n");
break;
}
else{
Q->a[Q->rear]=1;
Q->rear=(Q->rear+1)%MAXSIZE;
for(i=1;i<=k-1;i++){//输出中间k-2个元素!!!
Q->a[Q->rear]=Q->a[Q->front]+Q->a[(Q->front+1)%MAXSIZE];
Q->rear=(Q->rear+1)%MAXSIZE;
printf("%d ",Q->a[Q->front]);
Q->front=(Q->front+1)%MAXSIZE;
}
printf("%d ",Q->a[Q->front]);
Q->front=(Q->front+1)%MAXSIZE;
Q->a[Q->rear]=1;
Q->rear=(Q->rear+1)%MAXSIZE;
printf("\n");
}
}
}
}
核心部分:利用队列先进先出的特点输出杨辉三角的元素。
此外要掌握循环队列的使用方法:
Q->front=(Q->front+1)%MAXSIZE;//出队
Q->rear=(Q->rear+1)%MAXSIZE;//入队
注意:此代码实际上是利用队列中上一行的元素出队得出下一行的元素(入队)。在上面的代码中
for(i=1;i<=k-1;i++){//输出中间k-2个元素!!!
为什么是k-1而不是k-2?
此时要考虑的应该是计算机存储了下一行元素,因为只有存储了下一行元素,上一行元素才会全部输出,而此代码中的k仅表示“输出”第k行,所以具体考虑的是k+1行,而k+1行要入队存储(k+1)-2=k-1个中间元素,所以for的控制条件应该是i<=k-1.
例题5:有两个进程同时存在于一个程序中。其中第一个进程在屏幕上连续显示字符“A”,与此同时,程序不断检测键盘是否有输入,如果有的话,就读入用户输入的字符并保存到输入缓冲区中。在用户输入时,输入的字符并不立即回显到屏幕上。当用户输入一个逗号(,)或分号(;)时,表示第一个进程结束,第二个进程从缓冲区中读取那些已输入的字符并显示到屏幕上。第二个进程结束后,程序又进入第一个进程,重新显示字符“A”,同时用户又可以继续输入字符,直到用户输入一个分号键,才结束第一个进程,同时也结束整个程序。
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
//#include"queue.h"
#define MAXSIZE 10
typedef struct
{
char s[MAXSIZE];
int front;
int rear;
}SeqQueue;
void Initqueue(SeqQueue *Q);
int EnterQueue(char ch1,SeqQueue *Q);
int IsEmpty(SeqQueue *Q);
void DeleteQueue(SeqQueue *Q,char *ch2);
int main()
{
char ch1,ch2;
int flag;
SeqQueue *Q;
Initqueue(Q);
for(;;){
for(;;){//第一个进程
printf("A");
if(kbhit()){
ch1=getch();
if(ch1==','||ch1==';')break;
flag=EnterQueue(ch1,Q);
if(flag==0){
printf("队列已满!");
break;
}
}
}
while(!IsEmpty(Q)){//第二个进程
DeleteQueue(Q,&ch2);
putchar(ch2);
}
if(ch1==';')break;
}
return 0;
}
void Initqueue(SeqQueue *Q)
{
Q=(SeqQueue*)malloc(sizeof(SeqQueue));
Q->front=Q->rear=0;
}
int EnterQueue(char ch1,SeqQueue *Q)
{
if(Q->front!=(Q->rear+1)%MAXSIZE){
Q->s[Q->rear]=ch1;
Q->rear=(Q->rear+1)%MAXSIZE;
return 1;
}
else return 0;
}
int IsEmpty(SeqQueue *Q)
{
if(Q->front==Q->rear)return 1;
else return 0;
}
void DeleteQueue(SeqQueue *Q,char *ch2)
{
*ch2=Q->s[Q->front];
Q->front=(Q->front+1)%MAXSIZE;
}
函数kbhit()是: 检查当前是否有键盘输入,若有则返回一个非0值,否则返回0 。
getchar()与getch()的区别:
1.getchar();从键盘读取一个字符并bai输出,该函数du的返回值是输入zhi第一个字符的ASCII码;
若用户输入的是一连串dao字符,函数直到用户输入回车时结束,输入的字符连同回车一起存入键盘缓冲区。
若程序中有后继的getchar();函数,则直接从缓冲区逐个读取已输入的字符并输出,直到缓冲区为空时才重新读取用户的键盘输入。
2.getch();接受一个任意键的输入,不用按回车就返回。
该函数的返回值是所输入字符的ASCII码,且该函数的输入不会自动显示在屏幕上,需要putchar();函数输出显示。
getch();函数常用于中途暂停程序方便调试和查看。
3.getchar();和getch();的另一个区别就是所需要包含的头文件不同。
getchar();用#include<stdio.h>
getch(); 用#include<conio.h>
例题六:用列序递增法实现稀疏矩阵的转置
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
typedef struct
{
int row,col;
int e;
}Triple;
typedef struct
{
Triple data[MAXSIZE+1];
int m,n;
int len;
}MSTriple;
void Input(MSTriple *Q);
MSTriple *TransTriple(MSTriple *Q);
void Output(MSTriple *p);
int main()
{
MSTriple *Q,*p;
Q=(MSTriple*)malloc(sizeof(MSTriple));
Input(Q);
p=TransTriple(Q);
if(p!=NULL)Output(p);
return 0;
}
void Input(MSTriple *Q)
{
int m,n;
int x,y,z;
int i,j;
scanf("%d %d",&m,&n);
Q->m=m;
Q->n=n;
Q->len=0;
scanf("%d %d %d",&x,&y,&z);
for(i=1;x!=0&&y!=0&&z!=0&&i<=MAXSIZE;i++){
Q->data[i].row=x;
Q->data[i].col=y;
Q->data[i].e=z;
Q->len++;
scanf("%d %d %d",&x,&y,&z);
}
}
MSTriple *TransTriple(MSTriple *Q)
{
MSTriple *p;
int i,j,k=1;
p=(MSTriple *)malloc(sizeof(MSTriple));
p->len=Q->len;
p->m=Q->n;
p->n=Q->m;
if(p->len>0){
for(j=1;j<=p->n;j++){
for(i=1;i<=Q->len;i++){
if(Q->data[i].col==j){
p->data[k].row=Q->data[i].col;
p->data[k].col=Q->data[i].row;
p->data[k].e=Q->data[i].e;
k++;
}
}
}
return p;
}
else return NULL;
}
void Output(MSTriple *p)
{
int i;
for(i=1;i<=p->len;i++){
printf("%d %d %d\n",p->data[i].row,p->data[i].col,p->data[i].e);
}
}
核心部分:不断地遍历原三元组元素,对原三元组列序进行不断地筛选达到排序的效果,以至于实现新三元组的行数是递增的。
例题七:利用一次定位法实现矩阵的转置。
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
typedef struct
{
int row,col;
int e;
}Triple;
typedef struct
{
Triple data[MAXSIZE+1];
int m,n,len;
}MSTriple;
void InitTriple(MSTriple *A);
void Input(MSTriple *A);
MSTriple *TransTriple(MSTriple *A);
void Ouput(MSTriple *B);
int main()
{
MSTriple *A,*B;
A=(MSTriple*)malloc(sizeof(MSTriple));
InitTriple(A);
Input(A);
B=TransTriple(A);
Ouput(B);
return 0;
}
void InitTriple(MSTriple *A)
{
A->m=0;
A->n=0;
A->len=0;
}
void Input(MSTriple *A)
{
int m,n;
int x,y,z;
int i;
scanf("%d %d",&m,&n);
A->m=m;
A->n=n;
scanf("%d %d %d",&x,&y,&z);
for(i=1;x!=0&&y!=0&&z!=0&&A->len<=MAXSIZE;i++){
A->data[i].row=x;
A->data[i].col=y;
A->data[i].e=z;
A->len++;
scanf("%d %d %d",&x,&y,&z);
}
}
MSTriple *TransTriple(MSTriple *A)
{
MSTriple *B;
int i,j,k;
int num[100],position[100];
B=(MSTriple*)malloc(sizeof(MSTriple));
B->len=A->len;
B->m=A->n;
B->n=A->m;
//要遍历A中每一个非零元素,记录B中每行的元素个数
for(i=1;i<=A->n;i++)num[i]=0;//注意!!!
for(i=1;i<=A->len;i++)num[A->data[i].col]++;
//记录B中每行第一个元素的下标值
position[1]=1;
for(i=2;i<=A->n;i++)position[i]=position[i-1]+num[i-1];
//遍历A中的元素,进行转置操作
for(i=1;i<=A->len;i++){//核心部分
j=A->data[i].col;
k=position[j];
B->data[k].row=A->data[i].col;
B->data[k].col=A->data[i].row;
B->data[k].e=A->data[i].e;
position[j]++;
}
return B;
}
void Ouput(MSTriple *B)
{
int i;
for(i=1;i<=B->len;i++){
printf("%d %d %d\n",B->data[i].row,B->data[i].col,B->data[i].e);
}
}
注意1:在对num[100]进行初始化的时候,应该是要求B中每一行的num[ ]均初始化为0;不能仅初始化非零元素的num[ ]。如下:
正确:
for(i=1;i<=A->n;i++)num[i]=0;//注意!!!
错误:
for(i=0;i<=A->len;i++)num[A->data[i].col]=0;
如果使用了后面错误的代码,会造成后面position[i]=position[i-1]+num[i-1];计算错误,因为可能会遇到未进行初始化的num[i-1]!!!
注意2:顺序结构类型的对象初始化的时候要像链表初始化的时候一样:
void InitTriple(MSTriple **A)
{
*A=(MSTriple*)malloc(sizeof(MSTriple));
(*A)->m=0;
(*A)->n=0;
(*A)->len=0;
}
当然也可以在调用函数内部给对象分配空间,然后再调用一个初始化的函数,如此代码中的使用。
核心部分:position[col]存储的是每一行中第一个非零元素在B中的下标值,通过position[col]++;实现B中存储col行下一个非零元素。可以把position[col]看成是一个在col行上的一个指针,这个指针指向在col行上下一个非零元素在B中的下标值。