第一章 绪论
P8
例: 计算f=1!+2!+3!+…+n!,用C语言描述。
void factorsum(n)
int n;
{
int i,j;
int f,w;
f=0;
for (i=1;i〈=n;i++)
{
w=1;
for (j=1;j〈=i;j++)
w=w*j;
f=f+w;
}
return;
}
第二章 线性表
P16【算法2.1 顺序表的插入】
int Insert(Elemtype List[],int *num,int i,Elemtype x)
{/*在顺序表List[]中,*num为表尾元素下标位置,在第i个元素前插入数据元素x,若成功,返回TRUE,否则返回FALSE。*/
int j;
if (i<0||i>*num+1)
{printf("Error!"); /*插入位置出错*/
return FALSE;}
if (*num>=MAXNUM-1)
{printf("overflow!");
return FALSE;} /*表已满*/
for (j=*num;j>=i;j--)
List[j+1]=List[j]; /*数据元素后移*/
List[i]=x; /*插入x*/
(*num)++; /*长度加1*/
return TRUE;}
P18【算法2.2 顺序表的删除】
int Delete(Elemtype List[],int *num,int i)
{/*在线性表List[]中,*num为表尾元素下标位置,删除第i个长度,线性表的长度减1,若成功,则返回TRUE;否则返回FALSE。*/
int j;
if(i<0||i>*num)
{printf("Error!"); return FALSE; } /*删除位置出错!*/
for(j=i+1;j<=*num;j++)
List[j-1]=List[j]; /*数据元素前移*/
(*num)--; /*长度减1*/
return TRUE; }
P19 例:将有序线性表La={2,4,6,7,9},Lb={1,5,7,8},合并为Lc={1,2,4,5,6,7,7,8,9}。
void merge(Elemtype La[],Elemtype Lb[],Elemtype **Lc)
{ int i,j,k;
int La_length,Lb_length;
i=j=0;k=0;
La_length=Length(La);Lb_length=Length(Lb); /*取表La,Lb的长度*/
Initiate(Lc); /*初始化表Lc*/
While (i<=La_length&&j<=Lb_length)
{ a=get(La,i);b=get(Lb,j);
if(a<b) {insert(Lc,++k,a);++i;}
else {insert(Lc,++k,b);++j;}
} /*将La和Lb的元素插入到Lc中*/
while (i<=La_length) { a=get(La,i);insert(Lc,++k,a);}
while (j<=lb_length) { b=get(La,j);insert(Lc,++k,b); } }
P21例如:下面定义的结点类型中,数据域包含三个数据项:学号、姓名、成绩。
Struct student
{ char num[8]; /*数据域*/
har name[8]; /*数据域*/
int score; /*数据域*/
struct student *next; /*指针域*/
}
P21单链表结点结构定义为:
Typedef struct slnode
{ Elemtype data;
struct slnode *next;
}slnodetype;
slnodetype *p,*q,*s;
P21 【算法2.3 单链表的初始化】
int Initiate(slnodetype * *h)
{ if((*h=(slnodetype*)malloc(sizeof(slnodetype)))==NULL) return FALSE;
(*h)->next=NULL;
return TRUE; }
P22 【算法2.4 单链表的后插入】
{ s=(slnodetype*)malloc(sizeof(slnodetype));
s->data=x;
s->next=p->next;p->next=s;}
P22 【算法2.5 单链表的结点插入】
{q=head;
while(q->next!=p) q=q->next;
s=(slnodetype*)malloc(sizeof(slnodetype));
s->data=x;
s->next=p;
q->next=s;}
P23【算法2.6 单链表的前插入】
int insert(slnodetype *h,int i,Elemtype x)
{/*在链表h中,在第i个数据元素前插入一个数据元素x */
slnodetype *p,*q,*s;
int j=0;
p=h;
while(p!=NULL&&j<i-1) { p=q->next;j++; /*寻找第i-1个结点*/ }
if ( j!=i-1) {printf("Error!");return FALSE; /*插入位置错误*/}
if ((s=(slnodetype*)malloc(sizeof(slnodetype)))==NULL) return FALSE;
s->data=x;
s->next=p->next;
q->next=s;
return TRUE;}
P23例:下面C程序中的功能是,首先建立一个线性链表head={3,5,7,9},其元素值依次为从键盘输入正整数(以输入一个非正整数为结束);在线性表中值为x的元素前插入一个值为y的数据元素。若值为x的结点不存在,则将y插在表尾。
#include "stdlib.h"
#include "stdio.h"
struct slnode
{int data;
struct slnode *next;} /*定义结点类型*/
main()
{int x,y,d;
struct slnode *head,*p,*q,*s;
head=NULL; /*置链表空*/
q=NULL;
scanf("%d",&d); /*输入链表数据元素*/
while(d>0)
{p=(struct slnode*)malloc(sizeof(struct slnode)); /*申请一个新结点*/
p->data=d;
p->next=NULL;
if(head==NULL) head=p; /*若链表为空,则将头指针指向当前结点p*/
else q->next=p; /*链表不为空时,则将新结点链接在最后*/
q=p; /*将指针q指向链表的最后一个结点*/
scanf("%d",&d);}
scanf("%d,%d",&x,&y);
s=(struct slnode*)malloc(sizeof(struct slnode));
s->data=y;
q=head;p=q->next;
while((p!=NULL)&&(p->data!=x)) {q=p;p=p->next;} /*查找元素为x的指针*/
s->next=p;q->next=s; /*插入元素y*/
}
P24【算法2.7 单链表的删除】
int Delet(slnodetype *h,int i)
{ /*在链表h中删除第i个结点*/
slnodetype *p,*s;
int j;
p=h;j=0;
while(p->next!=NULL&&j<i-1)
{ p=p->next;j=j+1; /*寻找第i-1个结点,p指向其前驱*/}
if(j!=i-1)
{printf("Error!"); /*删除位置错误!*/
return FALSE; }
s=p->next;
p->next=p->next->next; /*删除第i个结点*/
free(s); /*释放被删除结点空间*/
return TRUE;
}
P25例:假设已有线性链表La,编制算法将该链表逆置。
void converse(slnodetype *head)
{slnodetype *p,*q;
p=head->next;
head->next=NULL;
while(p!=NULL)
{ q=p->next;
p->next=head->next;
head->next=p;
p=q; }
}
P27例:将两个循环链表首尾相接。La为第一个循环链表表尾指针,Lb为第二个循环链表表尾指针。合并后Lb为新链表的尾指针。
Void merge(slnodetype *La,slnodetype *Lb)
{ slnodetype *p;
p=La->next;
Lb->next= La->next;
La->next=p->next;
free(p);
}
P29【算法2.8 双向链表的插入】
int insert_dul(dlnodetype *head,int i,Elemtype x)
{/*在带头结点的双向链表中第i个位置之前插入元素x*/
dlnodetype *p,*s;
int j;
p=head;
j=0;
while (p!=NULL&&j<i)
{ p=p->next;
j++; }
if(j!=i||i<1)
{ printf("Error!");
return FALSE;}
if((s=(dlnodetype *)malloc(sizeof(dlnodetype)))==NULL) return FALSE;
s->data=x;
s->prior=p->prior; /*图中步骤①*/
p->prior->next=s; /*图中步骤②*/
s->next=p; /*图中步骤③*/
p->prior=s; /*图中步骤④*/
return TRUE;}
P30【算法2.9 双向链表的删除】
int Delete_dl(dlnodetype *head,int i)
{ dlnodetype *p,*s;
int j;
p=head;
j=0;
while (p!=NULL&&j<i)
{ p=p->next;
j++; }
if(j!=i||i<1)
{ printf("Error!");
return FALSE;}
s=p;
p->prior->next=p->next; /*图中步骤①*/
p->next->prior=p->prior; /*图中步骤②*/
free(s);
return TRUE;}
P32【算法2.10 多项式相加】
struct poly *add_poly(struct poly *Ah,struct poly *Bh)
{struct poly *qa,*qb,*s,*r,*Ch;
qa=Ah->next;qb=Bh->next; /*qa和qb分别指向两个链表的第一结点*/
r=qa;Ch=Ah; /*将链表Ah作为相加后的和链表*/
while(qa!=NULL&&qb!=NULL) /*两链表均非空*/
{ if (qa->exp==qb->exp) /*两者指数值相等*/
{x=qa->coef+qb->coef;
if(x!=0)
{ qa->coef=x;r->next=qa;r=qa;
s=qb++;free(s);qa++;
} /*相加后系数不为零时*/
else {s=qa++;free(s);s=qb++;free(s);} /*相加后系数为零时*/
}
else if(qa->exp<qb->exp){ r->next=qa;r=qa;qa++;} /*多项式Ah的指数值小*/
else {r->next=qb;r=qb;qb++;} /*多项式Bh的指数值小*/
}
if(qa==NULL) r->next=qb;
else r->next=qa; /*链接多项式Ah或Bh中的剩余结点*/
return (Ch);
}
第三章 栈和队列
P35相应的C语言函数是:
float fact(int n)
{float s;
if (n= =0||n= =1) s=1;
else s=n*fact(n-1);
return (s); }
P38用C语言定义的顺序存储结构的栈如下:
# define MAXNUM <最大元素数>
typedef struct {
Elemtype stack[MAXNUM];
int top; } sqstack;
P39【算法3.1 栈的初始化】
int initStack(sqstack *s)
{/*创建一个空栈由指针S指出*/
if ((s=(sqstack*)malloc(sizeof(sqstack)))= =NULL) return FALSE;
s->top= -1;
return TRUE;
}
P39【算法3.2 入栈操作】
int push(sqstack *s, Elemtype x)
{/*将元素x插入到栈s中,作为s的新栈顶*/
if(s->top>=MAXNUM-1) return FALSE; /*栈满*/
s->top++;
s->stack[s->top]=x;
return TRUE;
}
P39【算法3.3 出栈操作】
Elemtype pop(sqstack *s)
{/*若栈s不为空,则删除栈顶元素*/
Elemtype x;
if(s->top<0) return NULL; /*栈空*/
x=s->stack[s->top];
s->top--;
return x;
}
P39【算法3.4 取栈顶元素】
Elemtype getTop(sqstack *s)
{/*若栈s不为空,则返回栈顶元素*/
if(s->top<0) return NULL; /*栈空*/
return (s->stack[s->top]);
}
P40【算法3.5 判栈空操作】
int Empty(sqstack *s)
{/*栈s为空时,返回为TRUE;非空时,返回为FALSE*/
if(s->top<0) return TRUE;
return FALSE;
}
P40【算法3.6 栈置空操作】
void setEmpty(sqstack *s)
{/*将栈s的栈顶指针top,置为-1*/
s->top= -1;
}
P40 C语言定义的这种两栈共享邻接空间的结构如下:
Typedef struct {
Elemtype stack[MAXNUM];
int lefttop; /*左栈栈顶位置指示器*/
int righttop; /*右栈栈顶位置指示器*/
} dupsqstack;
P41【算法3.7 共享栈的初始化】
int initDupStack(dupsqstack *s)
{/*创建两个共享邻接空间的空栈由指针S指出*/
if (s=(dupsqstack*)malloc(sizeof(dupsqstack)))= =NULL) return FALSE;
s->lefttop= -1;
s->righttop=MAXNUM;
return TRUE;
}
P41【算法3.8 共享栈的入栈操作】
int pushDupStack(dupsqstack *s,char status,Elemtype x)
{*把数据元素x压入左栈(status='L')或右栈(status='R')*/
if(s->lefttop+1= =s->righttop) return FALSE; /*栈满*/
if(status='L') s->stack[++s->lefttop]=x; /*左栈进栈*/
else if(status='R') s->stack[--s->righttop]=x; /*右栈进栈*/
else return FALSE; /*参数错误*/
return TRUE;
}
P42【算法3.9 共享栈的出栈操作】
Elemtype popDupStack(dupsqstack *s,char status)
{/*从左栈(status='L')或右栈(status='R')退出栈顶元素*/
if(status= ='L')
{ if (s->lefttop<0)
return NULL; /*左栈为空*/
else return (s->stack[s->lefttop--]); /*左栈出栈*/
}
else if(status= ='R')
{ if (s->righttop>MAXNUM-1)
return NULL; /*右栈为空*/
else return (s->stack[s->righttop++]); /*右栈出栈*/
}
else return NULL; /*参数错误*/
}
P42链栈的C语言定义为:
typedef struct Stacknode
{
Elemtype data;
Struct Stacknode *next;
}slStacktype;
P43【算法3.10 单个链栈的入栈操作】
int pushLstack(slStacktype *top,Elemtype x)
{/*将元素x压入链栈top中*/
slStacktype *p;
if((p=(slStacktype *)malloc(sizeof(slStacktype)))= =NULL) return FALSE; /*申请一个结点*/
p->data=x; p->next=top; top=p; return TRUE;
}
P43【算法3.11 单个链栈的出栈操作】
Elemtype popLstack(slStacktype *top)
{/*从链栈top中删除栈顶元素*/
slStacktype *p;
Elemtype x;
if (top= =NULL) return NULL; /*空栈*/
p=top; top=top->next;
x=p->data;free(p);return x;
}
P44【算法3.12 多个链栈的入栈操作】
int pushDupLs(slStacktype *top[M],int i,Elemtype x)
{/*将元素x压入链栈top[i]中*/
slStacktype *p;
if((p=(slStacktype *)malloc(sizeof(slStacktype)))= =NULL) return FALSE; /*申请一个结点*/
p->data=x; p->next=top[i]; top[i]=p; return TRUE;
}
P44【算法3.13 多个链栈的出栈操作】
Elemtype popDupLs(slStacktype *top[M],int i)
{/*从链栈top[i]中删除栈顶元素*/
slStacktype *p;
Elemtype x;
if (top[i]= =NULL) return NULL; /*空栈*/
p=top[i]; top[i]=top[i]->next;
x=p->data;free(p);return x;
}
P47【算法3.14 中缀表达式变为后缀表达式】
# define MAXNUM 40
# define FALSE 0
# define TRUE 1
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef struct {
char stack[MAXNUM];
int top; } sqstack;
int initStack(sqstack *s)
{/*初始化栈*/
s->top=-1;
return TRUE;
}
int push(sqstack *s,char x)
{/*将元素x插入到栈s中,作为s的新栈顶*/
if(s->top>=MAXNUM-1) return FALSE; /*栈满*/
s->top++;
s->stack[s->top]=x;
return TRUE;
}
char pop(sqstack *s)
{/*若栈s不为空,则删除栈顶元素*/
char x;
if(s->top<0) return NULL; /*栈空*/
x=s->stack[s->top];
s->top--;
return x;
}
char gettop(sqstack *s)
{/*若栈s不为空,则返回栈顶元素*/
if(s->top<0) return NULL; /*栈空*/
return (s->stack[s->top]);
}
char precede(char x1,char x2)
{/*比较运算符x1与x2的优先*/
char result='<';
char sting[2];
sting[0]=x2;
sting[1]='\0';
if (((x1=='+'||x1=='-')&&(strstr("+-)#",sting)!=NULL))||
((x1=='*'||x1=='/')&&strstr("+-*/)#",sting)!=NULL)||
(x1==')'&&strstr("+-*/)#",sting)!=NULL))
{result='>';}
else if(x1=='('&&x2==')'||x1=='#'&&x2=='#')
{result='=';}
else if (x1==')'&&x2=='('||x1=='#'&&x2==')')
{result=' ';}
return result; }
main()
{sqstack *optr;
char s[80],c,y; int i=0;
optr=(sqstack *)malloc(sizeof(sqstack));
gets(s);
initStack(optr); push(optr,'#');
c=s[i];
while(c!='#'||gettop(optr)!='#')
{if(c!='+'&&c!='-'&&c!='*'&&c!='/'&&c!='('&&c!=')'&&c!='#')
{printf("%c",c);c=s[++i];
if(c=='\0') break;
}
else
switch (precede(gettop(optr),c))
{case '<':{push(optr,c);c=s[++i];break;}
case '=':{pop(optr);c=s[++i];break; }
case '>':{y=pop(optr);
printf("%c",y);
break;}}
} printf("%c",'#');
}
P51 用C语言定义的顺序存储结构的队列如下:
# define MAXNUM <最大元素数>
typedef struct {
Elemtype queue[MAXNUM];
int front; /*队头指示器*/
int rear; /*队尾指示器*/
} sqqueue;
P51【算法3.15 顺序队列的初始化】
int initQueue(sqqueue *q)
{/*创建一个空队列由指针q指出*/
if ((q=(sqqueue*)malloc(sizeof(sqqueue)))= =NULL) return FALSE;
q->front= -1;
q->rear=-1;
return TRUE;
}
P52【算法3.16 顺序队列的入队列操作】
int append(sqqueue *q,Elemtype x)
{/*将元素x插入到队列q中,作为q的新队尾*/
if(q->rear>=MAXNUM-1) return FALSE; /*队列满*/
q->rear++;
q->queue[q->rear]=x;
return TRUE;
}
P52【算法3.17 顺序队列的出队列操作】
Elemtype delete(sqqueue *q)
{/*若队列q不为空,则返回队头元素*/
Elemtype x;
if(q->rear= =q->front) return NULL; /*队列空*/
x=q->queue[++q->front];
return x;
}
P52【算法3.18 顺序队列的取头元素操作】
Elemtype getHead(sqqueue *q)
{/*若队列q不为空,则返回队头元素*/
if(q->rear= =q->front) return NULL; /*队列空*/
return (q->queue[s->front+1]);
}
P52【算法3.19 顺序队列的非空判断操作】
int Empty(sqqueue *q)
{/*队列q为空时,返回TRUE;否则返回FALSE*/
if (q->rear= =q->front) return TRUE;
return FALSE;
}
P53【算法3.20 顺序队列的求长度操作】
int length(sqqueue *q)
{/*返回队列q的元素个数*/
return(q->rear-q->front);
}
P54用C语言定义循环队列结构如下:
typedef struct
{Elemtype queue[MAXNUM];
int front; /*队头指示器*/
int rear; /*队尾指示器*/
int s; /*队列标志位*/
}qqueue;
P54【算法3.21 循环队列的初始化】
int initQueue(qqueue *q)
{/*创建一个空队列由指针q指出*/
if ((q=(qqueue*)malloc(sizeof(qqueue)))= =NULL) return FALSE;
q->front= MAXNUM;
q->rear=MAXNUM;
q->s=0; /*置队列空*/
return TRUE;
}
P55【算法3.22 循环队列的入队列操作】
int append(qqueue *q,Elemtype x)
{/*将元素x插入到队列q中,作为q的新队尾*/
if (( q->s= =1)&&(q->front= =q->rear)) return FALSE; /*队列满*/
q->rear++;
if (q->rear= =MAXNUM) q->rear=0;
q->queue[q->rear]=x;
q->s=1; /*置队列非空*/
return TRUE;
}
P55【算法3.23 循环队列的出队列操作】
Elemtype delete(qqueue *q)
{/*若队列q不为空,则返回队头元素*/
Elemtype x;
if (q->s= =0) retrun NULL; /*队列为空*/
q->front++;
if (q->front= =MAXNUM) q->front=0;
x=q->queue[q->front];
if (q->front = =q->rear) q->s=0; /*置队列空*/
return x; }
P56 用C语言定义链队列结构如下:
typedef struct Qnode
{Elemtype data;
struct Qnode *next;
}Qnodetype; /*定义队列的结点*/
typedef struct
{ Qnodetype *front;/*头指针*/
Qnodetype *rear; /*尾指针*/
}Lqueue;
P56【算法3.24 链队列的初始化】
int initLqueue(Lqueue *q)
{/*创建一个空链队列q*/
if ((q->front=(Qnodetype*)malloc(sizeof(Qnodetype)))= =NULL) return FALSE;
q->rear=q->front;
q->front->next=NULL;
return TRUE;
}
P56【算法3.25 链队列的入队列操作】
int Lappend(Lqueue *q,Elemtype x)
{/*将元素x插入到链队列q中,作为q的新队尾*/
Qnodetype *p;
if ((p=(Qnodetype*)malloc(sizeof(Qnodetype)))= =NULL) return FALSE;
p->data=x;
p->next=NULL; /*置新结点的指针为空*/
q->rear->next=p; /*将链队列中最后一个结点的指针指向新结点*/
q->rear=p; /*将队尾指向新结点*/
return TRUE;
}
P57【算法3.26 链队列的出队列操作】
Elemtype Ldelete(Lqueue *q)
{/*若链队列q不为空,则删除队头元素,返回其元素值*/
Elemtype x;
Qnodetype *p;
if(q->front->next= =NULL) return NULL; /*空队列*/
P=q->front->next; /*取队头*/
q->front->next=p->next; /*删除队头结点*/
x=p->data;
free(p);
return x;
}
第四章 串
P62 用字符数组存放字符串时,其结构用C语言定义如下:
#define MAXNUM <允许的最大的字符数>
typedef struct {
char str[MAXNUM];
int length; /*串长度*/
} stringtype; /* 串类型定义*/
P62 用链表存放字符串时,其结构用C语言定义如下:
typedef struct node{
char str;
struct node *next;
} slstrtype;
P63 用块链存放字符串时,其结构用C语言定义如下:
typedef struct node{
char str[4];
struct node *next;
} slstrtype;
P63 用堆存放字符串时,其结构用C语言定义如下:
typedef struct{
char *str;
int length;
} HSstrtype;
P65 C语言中用字符数组存储字符串时,结构定义如下:
#define MAXNUM 80
typedef struct {
char str[MAXNUM];
int length; /*串长度*/
} stringtype; /* 串类型定义*/
P65【算法4.1 在静态存储方式中求子串】
int substr(stringtype s1,stringtype * s2,int m,int n)
{int j,k;j=s1.length;
if(m<=0||m>j||n<0) {(*s2).str[0]='\0';(*s2).length=0;return FALSE; } /*参数错误*/
k=strlen(&s1.str[m-1]) ; /*求子串的长度*/
if (n>k) (*s2).length=k;
else (*s2).length=n; /*置子串的串长*/
for(j=0;j<=(*s2).length;j++,m++) (*s2).str[j]=s1.str[m-1];
(*s2).str[j]='\0'; /*置结束标记*/
return TRUE;
}
P66 假设链表中每个结点仅存放一个字符,则单链表定义如下
typedet struct node{
char str;
struct node *next;
} slstrtype;
P66【算法4.2 在链式存储方式中求子串】
int substr(slstrtype s1,slstrtype *s2,int m,int n)
{slstrtype *p,*q,*v;
int length1,j;
p=&s1;
for(lenght1=0;p->next!=NULL;p=p->next) length1++; /*求主串和串长*/
if(m<=0||m>length1||n<0) {s2=NULL;return FALSE;} /*参数错误*/
p=s1.next;
for(j=0;j<m;j++) p=p->next; /*找到子串和起始位置*/
s2=(slstrtype *)malloc(sizeof(slstrtype)); /*分配子串和第一个结点*/
v=s2;q=v;
for(j=0;j<n&&p->next!=NULL;j++) /*建立子串*/
{ q->str=p->str;
p=p->next;
q=(slstrtype *)malloc(sizeof(slstrtype));
v->next=q;
v=q;
}
q->str='\0';q->next=NULL; /*置子串和尾结点*/
return TRUE;
}
P67 堆存储结构用C语言定义为:
typedet struct{
char *str;
int length;
} HSstrtype;
P67【算法4.3 共享法求子串】
int substr(HSstrtype s1,HSstrtype *s2,int m,int n)
{ int j,k;
j=s1.length;
if(m<=0||m>j||n<0) {s2->length=0;return FALSE;} /*参数错误*/
k=strlen(s1.str+m); /*主串第m个位置开始之后的串长*/
if (n>k) s2->length=k;
else s2->length=n; /*置子串的串长*/
s2->str=s1.str+m; /*置子串的串首地址
return TRUE;
}
P67【算法4.4 重新赋值法求子串】
int substr(HSstrtype s1,HSstrtype *s2,int m,int n)
{ int j,k;
j=s1.length;
if(m<=0||m>j||n<0) {s2->length=0;return FALSE;} /*参数错误*/
k=strlen(s1.str+m); /*主串第m个位置开始之后的串长*/
if (n>k) s2->length=k;
else s2->length=n; /*置子串的串长*/
k=s2->length;
for(j=0;j<k;j++)
s2->str[j]=s1.str[m++]; /*复制字符*/
s2->str[j]='\0'; /*置结束符*/
return TRUE;
}
P68 例
main()
{int a,b,c;
scanf(〃%d,%d〃,&a,&b);
c=a+b;
printf("%d",c);
}
第五章 多维数组和广义表
P77 三元组表
#define maxsize 100 /*定义非零元的最大数目*/
struct node /*定义一个三元组*/
{
int i , j; /*非零元行、列号*/
int v; /*非零元值*/
};
struct sparmatrix /*定义稀疏矩阵*/
{
int rows,cols ; /*稀疏矩阵行、列数*/
int terms; /*稀疏矩阵非零元个数*/
node data [maxsize]; /*三元组表*/
};
P79 十字链表的数据类型描述如下:
struct linknode
{ int i, j;
struct linknode *cptr, *rptr;
union vnext /*定义一个共用体*/
{ int v; /*表结点使用V域,表示非零元值*/
struct linknode next; /*表头结点使用next域*/
} k; }
P81 (1)按照A的列序进行转置
#define maxsize 100
struct node
{
int i,j; /*定义三元组的行、列号*/
int v; /*三元组的值*/
};
struct sparmatrix
{
int rows,cols; /*稀疏矩阵的行、列数*/
int terms; /*稀疏矩阵的非零元个数*/
struct node data[maxsize]; /*存放稀疏矩阵的三元组表*/
};
void transpose(struct sparmatrix a)
{
struct sparmatrix b; /*b为a的转置*/
int ano,bno=0,col,i;
b.rows=a.cols; b.cols=a.rows;
b.terms=a.terms;
if (b.terms>0)
{
for ( col=0; col<a.cols; col++) /*按列号扫描*/
for( ano=0;ano<a.terms;ano++) /*对三元组扫描*/
if (a.data[ano].j==col) /*进行转置*/
{ b.data[bno].j=a.data[ano].i;
b.data[bno].i=a.data[ano].j;
b.data[bno].v=a.data[ano].v;
bno++;
}
}
for( i=0;i<a.terms;i++) /*输出转置后的三元组结果*/
printf("%5d%5d%5d\n",b.data[i].i,b.data[i].j,b.data[i].v);
}
void main()
{
int i;
struct sparmatrix a;
scanf("%d%d%d",&a.rows,&a.cols,&a.terms); /*输入稀疏矩阵的行、列数及非零元的个数*/
for( i=0;i<a.terms;i++)
scanf("%d%d%d",&a.data[i].i,&a.data[i].j,&a.data[i].v); /*输入转置前的稀疏矩阵的三元组*/
for(i=0;i<a.terms;i++)
printf("%5d%5d%5d\n",a.data[i].i,a.data[i].j,a.data[i].v); /*输出转置前的三元组结果*/
transpose( a); /*调用转置算法*/
}
P83 M稀疏矩阵的转置矩阵N的三元组表
#define maxsize 100
struct node
{
int i,j;
int v;
};
struct sparmatrix
{
int rows,cols;
int terms;
struct node data[maxsize];
};
void fastrans(struct sparmatrix a)
{
struct sparmatrix b;
int pot[maxsize],col,ano,bno,t,i;
b.rows=a.cols; b.cols=a.rows;
b.terms=a.terms;
if(b.terms>0)
{
for(col=0;col<=a.cols;col++)
pot[col]=0;
for( t=0;t<a.terms;t++) /*求出每一列的非零元个数*/
{
col=a.data[t].j;
pot[col+1]=pot[col+1]+1;
}
pot[0]=0;
for(col=1;col<a.cols;col++) /*求出每一列的第一个非零元在转置后的位置*/
pot[col]=pot[col-1]+pot[col];
for( ano=0;ano<a.terms;ano++) /*转置*/
{ col=a.data[ano].j;
bno=pot[col];
b.data[bno].j=a.data[ano].i;
b.data[bno].i=a.data[ano].j;
b.data[bno].v=a.data[ano].v;
pot[col]=pot[col]+1;
}
}
for( i=0;i<a.terms;i++)
printf("%d\t%d\t%d\n",b.data[i].i,b.data[i].j,b.data[i].v); /*输出转置后的三元组*/
}
void main()
{ struct sparmatrix a;
int i;
scanf("%d%d%d",&a.rows,&a.cols,&a.terms); /*输入稀疏矩阵的行、列数及非零元的个数*/
for( i=0;i<a.terms;i++)
scanf("%d%d%d",&a.data[i].i,&a.data[i].j,&a.data[i].v); /*输入转置前的三元组*/
for(i=0;i<a.terms;i++)
printf("%d\t%d\t%d\n",a.data[i].i,a.data[i].j,a.data[i].v); /*输出转置前的三元组*/
fastrans(a); /*调用快速转置算法*/
}
P85第二步,生成表中结点。算法描述如下:
#include<stdio.h>
#define maxsize 100
struct linknode
{
int i,j;
struct linknode *cptr,*rptr;
union vnext
{ int v;
struct linknode *next;} k;
};
struct linknode *creatlindmat( ) /*建立十字链表*/
{ int x, m, n, t, s, i, j, k;
struct linknode *p , *q, *cp[maxsize],*hm;
printf("请输入稀疏矩阵的行、列数及非零元个数\n");
scanf("%d%d%d",&m,&n,&t);
if (m>n) s=m; else s=n;
hm=(struct linknode*)malloc(sizeof(struct linknode)) ;
hm->i=m; hm->j=n;
cp[0]=hm;
for (i=1; i<=s;i++)
{ p=(struct linknode*)malloc(sizeof(struct linknode)) ;
p->i=0; p->j=0;
p->rptr=p; p->cptr=p;
cp[i]=p;
cp[i-1]->k.next=p;
}
cp[s]->k.next=hm;
for( x=1;x<=t;x++)
{ printf("请输入一个三元组(i,j,v)\n");
scanf("%d%d%d",&i,&j,&k); /*输入一个非零元的三元组*/
p=(struct linknode*)malloc(sizeof(struct linknode)); /*生成一个三元组的结点*/
p->i=i; p->j=j; p->k.v=k;
/*以下是将p插入到第i行链表中 */
q=cp[i];
while ((q->rptr!=cp[i]) &&( q->rptr->j<j))
q=q->rptr;
p->rptr=q->rptr;
q->rptr=p;
/*以下是将P插入到第j列链表中*/
q=cp[j];
while((q->cptr!=cp[j]) &&( q->cptr->i<i))
q=q->cptr;
p->cptr=q->cptr;
q->cptr=p;
}
return hm;
}
void main()
{ struct linknode *p,*q;
struct linknode *hm;
hm=creatlindmat( ); /*生成十字链表*/
p=hm->k.next;
while(p->k.next!=hm) /*输出十字链表*/
{ q=p->rptr;
while(q->rptr!=p)
{ printf("%3d%3d%3d\t",q->i,q->j,q->k.v);
q=q->rptr;
}
if(p!=q)
printf("%3d%3d%3d",q->i,q->j,q->k.v);
printf("\n");
p=p->k.next;
}
q=p->rptr;
while(q->rptr!=p)
{ printf("%3d%3d%3d\t",q->i,q->j,q->k.v);
q=q->rptr;
}
if(p!=q)
printf("%3d%3d%3d",q->i,q->j,q->k.v);
printf("\n");
}
P88 稀疏矩阵十字链表相加算法如下:
/*假设ha为A稀疏矩阵十字链表的头指针,hb为B稀疏矩阵十字链表的头指针*/
#include<stdio.h>
#define maxsize 100
struct linknode
{ int i,j;
struct linknode *cptr,*rptr;
union vnext
{ int v;
struct linknode *next;} k;
};
struct linknode creatlindmat( ) /*建立十字链表*/
{ int x, m, n, t, s, i, j, k;
struct linknode *p , *q, *cp[maxsize],*hm;
printf("请输入稀疏矩阵的行、列数及非零元个数\n");
scanf("%d%d%d",&m,&n,&t);
if (m>n) s=m; else s=n;
hm=(struct linknode*)malloc(sizeof(struct linknode)) ;
hm->i=m; hm->j=n;
cp[0]=hm;
for (i=1; i<=s;i++)
{ p=(struct linknode*)malloc(sizeof(struct linknode)) ;
p->i=0; p->j=0;
p->rptr=p; p->cptr=p;
cp[i]=p;
cp[i-1]->k.next=p;
}
cp[s]->k.next=hm;
for( x=1;x<=t;x++)
{ printf("请输入一个三元组(i,j,v)\n");
scanf("%d%d%d",&i,&j,&k);
p=(struct linknode*)malloc(sizeof(struct linknode));
p->i=i; p->j=j; p->k.v=k;
/*以下是将p插入到第i行链表中 */
q=cp[i];
while ((q->rptr!=cp[i]) &&( q->rptr->j<j))
q=q->rptr;
p->rptr=q->rptr;
q->rptr=p;
/*以下是将P插入到第j列链表中*/
q=cp[j];
while((q->cptr!=cp[j]) &&( q->cptr->i<i))
q=q->cptr;
p->cptr=q->cptr;
q->cptr=p;
}
return hm;
}
/* ha和hb表示的两个稀疏矩阵相加,相加的结果放入ha中*/
struct linknode *matadd(struct linknode *ha, struct linknode *hb)
{ struct linknode *pa, *pb, *qa, *ca,*cb,*p,*q;
struct linknode *hl[maxsize];
int i , j, n;
if((ha->i!=hb->i)||(ha->j!=hb->j))
printf("矩阵不匹配,不能相加\n");
else
{ p=ha->k.next; n=ha->j;
for (i=1;i<=n; i++)
{ hl[i]=p;
p=p->k.next;
}
ca=ha->k.next; cb=hb->k.next;
while(ca->i==0)
{pa=ca->rptr; pb=cb->rptr;
qa=ca;
while(pb->j!=0)
{ if((pa->j<pb->j)&&(pa->j!=0))
{ qa=pa; pa=pa->rptr;}
else if ((pa->j>pb->j)||(pa->j==0)) /*插入一个结点*/
{ p=(struct linknode*)malloc(sizeof(struct linknode));
p->i=pb->i; p->j=pb->j;
p->k.v=pb->k.v;
qa->rptr=p; p->rptr=pa;
qa=p; pb=pb->rptr;
j=p->j; q=hl[j]->cptr;
while((q->i<p->i)&&(q->i!=0))
{ hl[j]=q; q=hl[j]->cptr;}
hl[j]->cptr=p; p->cptr=q;
hl[j]=p;
}
else
{pa->k.v=pa->k.v+pb->k.v;
if(pa->k.v==0) /*删除一个结点*/
{ qa->rptr=pa->rptr;
j=pa->j; q=hl[j]->cptr;
while (q->i<pa->i)
{hl[j]=q; q=hl[j]->cptr;}
hl[j]->cptr=q->cptr;
pa=pa->rptr; pb=pb->rptr;
free(q);
}
else
{ qa=pa; pa=pa->rptr;
pb=pb->rptr;
}
}
}
ca=ca->k.next; cb=cb->k.next;
}
}
return ha;
}
void print(struct linknode *ha) /*输出十字链表*/
{ struct linknode *p,*q;
p=ha->k.next;
while(p->k.next!=ha)
{ q=p->rptr;
while(q->rptr!=p)
{ printf("%3d%3d%3d\t",q->i,q->j,q->k.v);
q=q->rptr;
}
if(p!=q)
printf("%3d%3d%3d",q->i,q->j,q->k.v);
printf("\n");
p=p->k.next;
}
q=p->rptr;
while(q->rptr!=p)
{ printf("%3d%3d%3d\t",q->i,q->j,q->k.v);
q=q->rptr;
}
if(p!=q)
printf("%3d%3d%3d",q->i,q->j,q->k.v);
printf("\n");
}
void main()
{
struct linknode *ha=NULL,*hb=NULL,*hc=NULL;
ha=creatlindmat( ); /*生成一个十字链表ha*/
hb=creatlindmat( ); /*生成另一个十字链表hb*/
printf("A:\n"); /*输出十字链表ha*/
print(ha);printf("\n");
printf("B:\n"); /*输出十字链表hb*/
print(hb);printf("\n");
hc=matadd(ha,hb); /*十字链表相加*/
printf("A+B:\n"); /*输出相加后的结果*/
print(hc);printf("\n");
}
P94 数据类型描述如下:
#define elemtype char
struct node1
{ int atom;
struct node1 *link;
union
{
struct node1 *slink;
elemtype data;
} ds;
}
P95 数据类型描述如下:
struct node2
{ elemtype data;
struct node2 *link1,*link2;
}
P96 求广义表的深度depth(LS)
int depth(struct node1 *LS)
{
int max=0,dep;
while(LS!=NULL)
{ if(LS->atom==0) //有子表
{ dep=depth(LS->ds.slink);
if(dep>max) max=dep;
}
LS=LS->link;
}
return max+1;
}
P96 广义表的建立creat(LS)
void creat(struct node1 *LS)
{
char ch;
scanf("%c",&ch);
if(ch=='#')
LS=NULL;
else if(ch=='(')
{LS=(struct node*)malloc(sizeof(struct node));
LS->atom=0;
creat(LS->ds.slink);
}
else
{ LS=(struct node*)malloc(sizeof(struct node));
LS->atom=1;
LS->ds.data=ch;
}
scanf("%c",&ch);
if(LS==NULL);
else if(ch==',')
creat(LS->link);
else if((ch==')')||(ch==';'))
LS->link=NULL;
}
P97 输出广义表print(LS)
void print(struct node1 *LS)
{
if(LS->atom==0)
{
printf("(");
if(LS->ds.slink==NULL)
printf("#");
else
print(LS->ds.slink);
}
else
printf("%c ",LS->ds.data);
if(LS->atom==0)
printf(")");
if(LS->link!=NULL)
{
printf(";");
print(LS->link);
}
}
P98 该算法的时间复杂度为O(n)。整个完整程序如下:
#include<stdio.h>
#define elemtype char
struct node1
{ int atom;
struct node1 *link;
union
{
struct node1 *slink;
elemtype data;
} ds;
};
void creat(struct node1 LS) /*建立广义表的单链表*/
{
char ch;
scanf("%c",&ch);
if(ch=='#')
LS=NULL;
else if(ch=='(')
{LS=(struct node1*)malloc(sizeof(struct node1));
LS->atom=0;
creat(LS->ds.slink);
}
else
{ LS=(struct node1*)malloc(sizeof(struct node1));
LS->atom=1;
LS->ds.data=ch;
}
scanf("%c",&ch);
if(LS==NULL);
else if(ch==',')
creat(LS->link);
else if((ch==')')||(ch==';'))
LS->link=NULL;
}
void print(struct node1 LS) /*输出广义单链表*/
{
if(LS->atom==0)
{
printf("(");
if(LS->ds.slink==NULL)
printf("#");
else
print(LS->ds.slink);
}
else
printf("%c",LS->ds.data);
if(LS->atom==0)
printf(")");
if(LS->link!=NULL)
{
printf(";");
print(LS->link);
}
}
int depth(struct node1 LS) /*求广义表的深度*/
{
int max=0;
while(LS!=NULL)
{ if(LS->atom==0)
{ int dep=depth(LS->ds.slink);
if(dep>max) max=dep;
}
LS=LS->link;
}
return max+1;
}
main()
{ int dep;
struct node1 *p=NULL;
creat(p); /*建立广义表的单链表*/
print(p); /*输出广义单链表*/
dep=depth(p); /*求广义表的深度*/
printf("%d\n",dep);
}
第六章 树
P109 二叉链表的结点类型定义如下:
typedef struct btnode
{ anytype data;
struct btnode *Lch,*Rch;
}tnodetype;
P109 三叉链表的结点类型定义如下:
typedef struct btnode3
{ anytype data;
struct btnode *Lch,*Rch,*Parent ;
}tnodetype3;
P112 C语言的先序遍历算法:
void preorder (tnodetype *t)
/*先序遍历二叉树算法,t为指向根结点的指针*/
{ if (t!=NULL)
{printf("%d ",t->data);
preorder(t->lch);
preorder(t->rch);
}
}
P113 C语言的中序遍历算法:
void inorder(tnodetype *t)
/*中序遍历二叉树算法,t为指向根结点的指针*/
{
if(t!=NULL)
{inorder(t->lch);
printf("%d ",t->data);
inorder(t->rch);
}
}
P113 C语言的后序遍历算法:
void postorder(tnodetype *t)
/*后序遍历二叉树算法,t为指向根结点的指针*/
{
if(t!=NULL)
{ postorder(t->lch);
postorder(t->rch);
printf("%d ",t->data);
}
}
P114 如果引入队列作为辅助存储工具,按层次遍历二叉树的算法可描述如下:
void levelorder(tnodetype *t)
/*按层次遍历二叉树算法,t为指向根结点的指针*/
{tnodetype q[20]; /*辅助队列*/
front=0;
rear=0; /*置空队列*/
if (t!=NULL)
{ rear++;
q[rear]=t; /*根结点入队*/
}
while (front!=rear)
{ front++;
t=q [front];
printf ("%c\n",t->data);
if (t->lch!=NULL) /*t的左孩子不空,则入队*/
{ rear++;
q [rear]=t->lch;
}
if (t->rch!=NULL) /*t的右孩子不空,则入队*/
{ rear++;
q [rear]=t->rch;
}
}
}
P115 以中序遍历的方法统计二叉树中的结点数和叶子结点数,算法描述为:
void inordercount (tnodetype *t)
/*中序遍历二叉树,统计树中的结点数和叶子结点数*/
{ if (t!=NULL)
{ inordercount (t->lch); /*中序遍历左子树*/
printf ("%c\n",t->data); /*访问根结点*/
countnode++; /*结点计数*/
if ((t->lch==NULL)&&(t->rch==NULL))
countleaf++; /*叶子结点计数*/
inordercount (t->rch); /*中序遍历右子树*/
}
}
P115 可按如下方法计算一棵二叉树的深度:
void preorderdeep (tnodetype *t,int j)
/*先序遍历二叉树,并计算二叉树的深度*/
{ if (t!=NULL)
{ printf ("%c\n",t->data); /*访问根结点*/
j++;
if (k<j) k=j;
preorderdeep (t->lch,j); /*先序遍历左子树*/
preorderdeep (t->rch,j); /*先序遍历右子树*/
}
}
P117 线索二叉树的结点类型定义如下:
struct nodexs
{anytype data;
struct nodexs *lch, *rch;
int ltag,rtag; /*左、右标志域*/
}
P117 中序次序线索化算法
void inorderxs (struct nodexs *t)
/*中序遍历t所指向的二叉树,并为结点建立线索*/
{ if (t!=NULL)
{ inorderxs (t->lch);
printf ("%c\n",t->data);
if (t->lch!=NULL)
t->ltag=0;
else { t->ltag=1;
t->lch=pr;
} /*建立t所指向结点的左线索,令其指向前驱结点pr*/
if (pr!=NULL)
{ if (pr->rch!=NULL)
pr->rtag=0;
else { pr->rtag=1;
pr->rch=p;
}
} /*建立pr所指向结点的右线索,令其指向后继结点p*/
pr=p;
inorderxs (t->rch);
}
}
P118 在中根线索树上检索某结点的前驱结点的算法描述如下:
struct nodexs * inpre (struct nodexs *q)
/*在中根线索树上检索q所指向的结点的前驱结点*/
{ if (q->ltag==1)
p=q->lch;
else { r=q->lch;
while (r->rtag!=1)
r=r->rch;
p=r;
}
return (p);
}
P119 在中根线索树上检索某结点的后继结点的算法描述如下:
struct nodexs * insucc (struct nodexs *q)
/*在中根线索树上检索q所指向的结点的后继结点*/
{ if (q->rtag==1)
p=q->rch;
else { r=q->rch;
while (r->ltag!=1)
r=r->lch;
p=r;
}
return (p);
}
P120 算法程序用C语言描述如下:
void insertbst(t,s)
/*将指针s所指的结点插入到以t为根指针的二叉树中*/
{ if (t==NULL)
t=s; /*若t所指为空树,s所指结点为根*/
else if (s->data < t->data)
insertbst(t->lch,s); /*s结点插入到t的左子树上去*/
else
insertbst(t->rch,s); /*s结点插入到t的右子树上去*/
}
P121 二叉排序树结点删除算法的C语言描述如下:
void delnode(bt,f,p)
/*bt为一棵二叉排序树的根指针,p指向被删除结点,f指向其双亲*/
/*当p=bt时f为NULL*/
{ fag=0; /*fag=0时需修改f指针信息,fag=1时不需修改*/
if (p->lch==NULL)
s=p->rch; /*被删除结点为叶子或其左子树为空*/
else if (p->rch==NULL)
s=p->lch;
else { q=p; /*被删除结点的左、右子树均非空*/
s=p->lch;
while (s->rch!=NULL)
{ q=s;
s=s->rch;
} /*寻找s结点*/
if (q=p)
q->lch=s->lch;
else q->rch=s->lch;
p->data=s->data; /*s所指向的结点代替被删除结点*/
DISPOSE(s);
Fag=1;
}
if (fag=0) /*需要修改双亲指针*/
{ if (f=NULL)
bt=s; /*被删除结点为根结点*/
else if (f->lch=p)
f->lch=s;
else f->rch=s;
DISPOSE(p); /*释放被删除结点*/
}
}
第七章 图
P134 用邻接矩阵表示法表示图,除了存储用于表示顶点间相邻关系的邻接矩阵外,通常还需要用一个顺序表来存储顶点信息。其形式说明如下:
# define n 6 /*图的顶点数*/
# define e 8 /*图的边(弧)数*/
typedef char vextype; /*顶点的数据类型*/
typedef float adjtype; /*权值类型*/
typedef struct
{vextype vexs[n];
adjtype arcs[n][n];
}graph;
P135 建立一个无向网络的算法。
CREATGRAPH(ga) /*建立无向网络*/
Graph * ga;
{
int i,j,k;
float w;
for(i=0;i<n;i++ )
ga ->vexs[i]=getchar(); /*读入顶点信息,建立顶点表*/
for(i=0;i<n;i++ )
for(j=0;j<n;j++)
ga ->arcs[i][j]=0; /*邻接矩阵初始化*/
for(k=0;k<e;k++) /*读入e条边*/
(scanf("%d%d%f",&I,&j,&w); /*读入边(vi,vj)上的权w */
ga ->arcs[i][j]=w;
ga - >arcs[j][i]=w;
}
} /*CREATGRAPH*/
P136 邻接表的形式说明及其建立算法:
typedef struct node
{int adjvex; /*邻接点域*/
struct node * next; /*链域*/
}edgenode; /*边表结点*/
typedef struct
{vextype vertex; /*顶点信息*/
edgenode link; /*边表头指针*/
}vexnode; /*顶点表结点*/
vexnode ga[n];
CREATADJLIST(ga) /*建立无向图的邻接表*/
Vexnode ga[ ];
{int i,j,k;
edgenode * s;
for(i=o;i<n;i++= /*读入顶点信息*/
(ga[i].vertex=getchar();
ga[i].1ink=NULL; /*边表头指针初始化*/
}
for(k=0;k<e;k++= /*建立边表*/
{scanf("%d%d",&i,&j); /*读入边(vi , vj)的顶点对序号*/
s=malloc(sizeof(edgenode)); /*生成邻接点序号为j的表结点*s */
s-> adjvex=j;
s- - >next:=ga[i].Link;
ga[i].1ink=s; /*将*s插入顶点vi的边表头部*/
s=malloc(size0f(edgende)); /*生成邻接点序号为i的边表结点*s */
s ->adjvex=i;
s ->next=ga[j].1ink;
ga[j].1ink=s; /*将*s插入顶点vj的边表头部*/
}
} /* CREATADJLIST */
P139 分别以邻接矩阵和邻接表作为图的存储结构给出具体算法,算法中g、g1和visited为全程量,visited的各分量初始值均为FALSE。
int visited[n] /*定义布尔向量visitd为全程量*/
Graph g; /*图g为全程量*/
DFS(i) /*从Vi+1出发深度优先搜索图g,g用邻接矩阵表示*/
int i;
{ int j;
printf("node:%c\n" , g.vexs[i]); /*访问出发点vi+1 */
Visited[i]=TRUE; /*标记vi+l已访问过*/
for (j=0;j<n;j++) /*依次搜索vi+1的邻接点*/
if((g.arcs[i][j]==1) &&(! visited[j]))
DFS(j); /*若Vi+l的邻接点vj+l未曾访问过,则从vj+l出发进行深度优先搜索*/
} /*DFS*/
vexnode gl[n] /*邻接表全程量*/
DFSL(i) /*从vi+l出发深度优先搜索图g1,g1用邻接表表示*/
int i;
{ int j;
edgenode * p;
printf("node:%C\n" ,g1[i].vertex);
vistited[i]=TRUE;
p=g1[i].1ink; /*取vi+1的边表头指针*/
while(p !=NULL) /*依次搜索vi+l的邻接点*/
{
if(! Vistited[p ->adjvex])
DFSL(p - >adjvex); /*从vi+1的未曾访问过的邻接点出发进行深度优先搜索*/
p=p - >next; /*找vi+l的下一个邻接点*/
}
} /* DFSL */
P142 以邻接矩阵和邻接表作为图的存储结构,分别给出宽度优先搜索算法。
BFS(k) /*从vk+l出发宽度优先搜索图g,g用邻接矩阵表示,visited为访问标志向量*/
int k;
{ int i,j;
SETNULL(Q); /*置空队Q */
printf("%c\n",g.vexs[k]); /*访问出发点vk+l*x/
visited[k]=TRUE; /*标记vk+l已访问过*/
ENQUEUE(Q,K); /*已访问过的顶点(序号)入队列*/
While(!EMPTY(Q)) /*队非空时执行*/
{i=DEQUEUE(Q); /*队头元素序号出队列*/
for(j=0;j<n;j++)
if((g.arcs[i][j]==1)&&(! visited[j]))
{printf("%c\n" , g.vexs[j]); /*访问vi+l的未曾访问的邻接点vj+l */
visited[j]=TRUE;
ENQUEUE(Q,j); /*访问过的顶点入队*/
}
}
} /* BFS */
BFSL(k) /*从vk+l出发宽度优先搜索图g1,g1用邻接表表示*/
int k
{ int i;
edgenode * p;
SETNULL(Q);
printf("%c\n" , g1[k].vertex);
visited[k]=TRUE;
ENQUEUE(Q,k);
while(! EMPTY(Q));
{ i=DEQUEUE(Q);
p=g1[i].1ink /*取vi+l的边表头指针*/
while(p !=NULL) /*依次搜索vi+l的邻接点*/
{ if( ! visited[p - >adjvex]) /*访问vi+l的未访问的邻接点*/
{ printf{"%c\n" , g1[p - >adjvex].vertex};
visited[p - >adjvex]=TRUE;
ENQUEUE(Q,p - >adjvex); /*访问过的顶点入队*/
}
p=p - >next; /*找vi+l的下一个邻接点*/
}
}
} /*BFSL*/
P148 在对算法Prim求精之前,先确定有关的存储结构如下:
typdef struct
{Int fromvex,endvex; /*边的起点和终点*/
float length; /*边的权值*/
} edge;
float dist[n][n]; /*连通网络的带权邻接矩阵*/
edgeT[n-1]; /*生成树*/
P149 抽象语句(1)可求精为:
for(j=1;j<n;j++) /*对n-1个蓝点构造候选紫边集*/
{T[j-1].fromvex=1}; /*紫边的起点为红点*/
T[j-1].endvex=j+1; /*紫边的终点为蓝点*/
T[j-1].1ength=dist[0][j]; /*紫边长度*/
}
P149 抽象语句(3)所求的第k条最短紫边可求精为:
min=max; /*znax大于任何边上的权值*/
for (j=k;j<n-1;j++) /*扫描当前候选紫边集T[k]到T[n-2],找最短紫边*/
if(T[j].1ength<min)
{min=T[j].1ength;m=j; /*记录当前最短紫边的位置*/
}
P149 抽象语句(4)的求精:
e=T[m];T[m]=T[k];T[k]=e, /* T[k]和T[m]交换*/
v=T[kl.Endvex]; /* v是刚被涂红色的顶点*/
P149 抽象语句(5)可求精为:
for(j=k+1;j<n-1;j++) /*调整候选紫边集T[k+1]到T[n-2]*/
{d=dist[v-1][T[j].endvex-1]; /*新紫边的长度*/
if(d<T[j].1ength) /*新紫边的长度小于原最短紫边*/
{T[j].1ength=d;
T[j].fromvex=v; /*新紫边取代原最短紫边*/
}
}
P150 完整的算法:
PRIM() /*从第一个顶点出发构造连通网络dist的最小生成树,结果放在T中*/
{int j , k , m , v , min , max=l0000;
float d;
edge e;
for(j=1;j<n;j++) /*构造初始候选紫边集*/
{T[j-1].formvex=1; /*顶点1是第一个加入树中的红点*/
T[j-1].endvex=j+1;
T[j-1].length=dist[o][j];
}
for(k=0;k<n-1;k++) /*求第k条边*/
{min=max;
for(j=k;j<n-1;j++) /*在候选紫边集中找最短紫边*/
if(T[j].1ength<min)
{min=T[j].1ength;
m=j;
} /*T[m]是当前最短紫边*/
}
e=T[m];T[m]=T[k];T[k]=e; /*T[k]和T[m]交换后,T[k]是第k条红色树边*/
v=T[k].endvex ; /* v是新红点*/
for(j=k+1;j<n-1;j++) /*调整候选紫边集*/
{d=dist[v-1][T[j].endvex-1];
if(d<T[j].1ength);
{T[j].1ength=d;
T[j].fromvex=v;
}
}
} /* PRIM */
P151 Kruskl算法的粗略描述:
T=(V,φ);
While(T中所含边数<n-1)
{从E中选取当前最短边(u,v);
从E中删去边(u,v);
if((u,v)并入T之后不产生回路,将边(u,v)并入T中;
}
P153 迪杰斯特拉算法实现。算法描述如下:
#define max 32767 /*max代表一个很大的数*/
void dijkstra (float cost[][n],int v)
/*求源点v到其余顶点的最短路径及其长度*/
{ v1=v-1;
for (i=0;i<n;i++)
{ dist[i]=cost[v1][i]; /*初始化dist*/
if (dist[i]<max)
pre[i]=v;
else pre[i]=0;
}
pre[v1]=0;
for (i=0;i<n;i++)
s[i]=0; /*s数组初始化为空*/
s[v1]=1; /*将源点v归入s集合*/
for (i=0;i<n;i++)
{ min=max;
for (j=0;j<n;j++)
if (!s[j] && (dist[j]<min))
{ min=dist[j];
k=j;
} /*选择dist值最小的顶点k+1*/
s[k]=1; /*将顶点k+1归入s集合中*/
for (j=0;j<n;j++)
if (!s[j]&&(dist[j]>dist[k]+cost[k][j]))
{ dist[j]=dist[k]+cost[k][j]; /*修改 V-S集合中各顶点的dist值*/
pre[j]=k+1; /*k+1顶点是j+1顶点的前驱*/
}
} /*所有顶点均已加入到S集合中*/
for (j=0;j<n;j++) /*打印结果*/
{ printf("%f\n%d",dist[j],j+1;);
p=pre[j];
while (p!=0)
{ printf("%d",p);
p=pre[p-1];
}
}
}
P155 弗洛伊德算法可以描述为:
A(0)[i][j]=cost[i][j]; //cost为图的邻接矩阵
A(k)[i][j]=min{A(k-1) [i][j],A(k-1) [i][k]+A(k-1) [k][j]}
其中 k=1,2,...,n
P155 弗洛伊德算法实现。算法描述如下:
int path[n][n]; /*路径矩阵*/
void floyd (float A[][n],cost[][n])
{ for (i=0;i<n;i++) /*设置A和path的初值*/
for (j=0;j<n;j++)
{ if (cost[i][j]<max)
path[i][j]=j;
else { path[i][j]=0;
A[i][j]=cost[i][j];
}
}
for (k=0;k<n;k++)
/*做n次迭代,每次均试图将顶点k扩充到当前求得的从i到j的最短路径上*/
for (i=0;i<n;i++)
for (j=0;j<n;j++)
if (A[i][j]>(A[i][k]+A[k][j])) /*修改长度和路径*/
{ A[i][j]=A[i][k]+A[k][j];
path[i][j]=path[i][k];
}
for (i=0;i<n;i++) /*输出所有顶点对i,j之间的最短路径长度及路径*/
for (j=0;j<n;j++)
{ printf ("%f",A[i][j]); /*输出最短路径的长度*/
next=path[i][j]; /*next为起点i的后继顶点*/
if (next==0) /*i无后继表示最短路径不存在*/
printf ("%d to %d no path.\n",i+1,j+1);
else { printf ("%d",i+1); /*最短路径存在*/
while (next!=j+1) /*打印后继顶点,然后寻找下一个后继顶点*/
{ printf ("%d",next);
next =path[next-1][j];
}
printf ("%d\n",j+1);
}
}
}
第八章 查找
P163 具体实现图8-1框图的程序段如下:
Void seqsrch(struct node r[],int n,int k)
{ int i=1;
r[n+1].key=k; /*设置边界*/
while (r[i].key!=k)
i=i+1;
if (i<=n)
printf("%3d,it is r[%2d]",k,i);
else printf("%3d not found",k );
}
P164 设表的长度为n,表的被查找部分的头为low,尾为high,初始时,low=1,high=n,k为关键字的值。具体算法如下:
Void binsrch(struct node r[ ],int n,int k)
{ int mid,low,high,find;
low=1; high=n;find=0; /*置区间初值*/
while ((low<=high) && (!find))
{ mid=(low+high)/2; /*求中点*/
if (k= = r[mid].key)
find=1; /*已查到*/
else if(k>r[mid].key )
low=mid+1; /*在后半区间查找*/
else high=mid-1; /*在前半区间查找*/
}
if (find)
return (mid); /*查找成功,返回找到元素的位置*/
else return (0); /*查找不成功,返回0标记*/
}
P170 下面是线性探测法的算法,请注意,算法中设立了一个查找的边界值i,当顺序探测已超过表长,则要翻转到表首继续查找,直到查到i位置才是真正的查完全表。为编程方便,令i=j-1。
Define m 100; /*哈希表的长度*/
Struct hash
{int key;
}HT[m];
Void linehash(struct hash HT[ ],int k,int p)
{j=k%p;i=j-1;
while ((HT[j].key!=NULL)&&(HT[j].key!=k)&&(j!=i))
j=(j+1)%m; /*解决冲突*/
if (HT[j].key==k)
printf("succ!%d,%d\n",k,j);
else if (j==i)
printf("overflow!\n"); /*溢出*/
else HT[j].key=k; /*插入k*/
}
P171 链地址散列表的具体算法描述如下:
Define m 100; /*表长*/
Struct node
{int key;
struct node * next;
}HT[m];
Void linkhash(struct node HT[ ],int k,int p)
{struct node * p,* r,* s;
j=k%p;
if(HT[j].key==0)
{HT[j].key=k;
HT[j].next=NULL;
}
else if(HT[j].key==k)
printf("succ!%d,%d\n",j,k);
else {q=HT[j].next;
while(q!=NULL)&&(q->key!=k)
{r=q;
q=q->next;
}
if(q==NULL)
{s=(struct node *)malloc(sizeof(struct node));
s->key=k;
s->next=NULL;
r->next=s;
}
else printf("succ!%d,%d\n",j,k);
}
第九章 排序
P175 线性插入排序
void insertsort(struct node r[ n+1],int n)
/* r[n+1]为一维数组,其中r[0]为监视哨,r[1]到r[n]为待排序的n个记录,排序好的记录仍放在r中*/
{ for(i=2;i<=n;i++) /*共进行n-1趟*/
{ r[0]=r[i]; /*r[0]为监视哨,也可做下边循环结束标志*/
j=i-1;
while(r[j].key>r[0].key)
{ r[j+1]=r[j];
j--;
}
r[j+1]=r[0];
}
}
P176 折半插入排序
void binarysort(struct node r[ n+1],int n)
/*按关键字递增的次序对记录r[1],r[2],......,r[n]进行折半插入排序 */
{ for(i=2;i<=n;i++)
{ r[0]=r[i];
l=1;
h=i-1;
while(l<=h)
{ mid=(l+h)/2;
if(r[0].key<r[mid].key)
h=mid-1;
else l=mid+1;
}
for(j=i-1;j>=l;j--)
r[j+1]=r[j];
r[l]=r[0];
}
}
P178 希尔排序
rectype R[n+d1]; /* R[d1-1]为d1个监视哨*/
int d[t]; /* d[0]到d[t-1]为增量序列*/
SHELLSORT(R,d)
Rectype R[ ];
int d[ ];
{int i,j,k,h;
rectype temp;
int maxint=32767; /*机器中最大整数*/
for (i=0;i<d[0];i++)
R[i].key=-maxint; /*设置哨兵*/
K=0;
Do{
H=d[k]; /*取本趟增量*/
For(i=h+di;i<n+d1;i++) /*R[h+d1]到R[n+d1-1]插入当前有序区*/
{temp=R[i]}; /*保存待插入记录R[i]*/
j=i-h;
while(temp.key<R[j].key) /*查找正确的插入位置*/
{R[j+h]=R[j]}; /*后移记录*/
j=j-h; /*得到前一记录位置*/
}
R[j+h]=temp; /*插入R[i]*/
} /*本趟排序完成*/
k++;
} while (h!=1); /*增量为1排序后终止算法*/
} /*SHELLSORT*/
P180 选择排序算法如下:
void selectsort(struct node r[n+1],int n)
/*对记录数组r[1]至r[n]进行选择排序*/
{ for(i=1;i<n;i++)
{ min=i;
for(j=i+1;j<=n;j++) /*选择最小元*/
if (r[j].key<r[min].key)
min=j;
if(min!=i)
{ temp=r[min];
r[min]=r[i];
r[i]=temp;
}
}
}
P183 把左、右子树都是堆的顺序二叉树调整为一个堆,其算法描述如下:
void adjust(struct node r[m+1],int m)
/* 将文件(r[1],r[2],...,r[m])解释为一棵顺序二叉树,将其中以r[i]为根结点的二叉树调整
为一个堆,设以r[i]为根的二叉树的左,右子树已是堆,1≤i≤1[m/2] */
{ x=r[i];j=2*i; /*求出r[i]的左孩子r[2*i],即r[j] */
while (j<=m) /*有左孩子*/
{ if ((j<m) &&(r[j].key<r[j+1].key)) /*比较左、右孩子*/
j=j+1; /*左孩子<右孩子*/
if (x.key<r[j].key) /*比较根结点和它的大孩子*/
{ r[i]=r[j]; /*大孩子上移到它的双亲位置*/
i=j; /*今 r[j]为根结点*/
j=2*i; /*求出左孩子*/
}
else j=m+1 /*根不小于它的任一孩子时,强迫退出while循环*/
}
r[i]=x; /*将存放在x中的根结点放到r[i]中*/
}
P183 堆排序算法如下:
void heapsort (struct node r[n+1],int m)
/*对记录数组r[1]至r[n]进行堆排序*/
{ for(i=n/2;i>=1;i--)
adjust(r,i,n); /*建立初始堆*/
for(j=n;j>=2;j--)
{ x=r[1]; r[1]=r[j]; /*交换根结点和堆的最后一个结点*/
r[j]=x;
Adjust (r,1,j-1) /*将r [1]至r[j-1]调整为堆*/
}
}
P185 一次划分及其排序的算法。
int partition(r,1,h) /*返回划分后被定的基准记录的位置*/
rectype R[ ]; /*对无序区R[1]到R[h]做划分*/
int 1,h;
{int i,j;
rectype temp;
i=1;j=h temp=R[i]; /*初始化,temp为基准*/
Do{
While((R[j].key>=temp.key) && (i<j))
j--; /*从右向左扫描,查找第1个关键字小于temp.key的记录*/
if(i<j) R[i++]=R[j]; /*交换R[i]和R[j]*/
while((R[i].key<=temp.key) && (i<j))
i++; /*从左向右扫描,查找第1个关键字大于temp.key的记录*/
if(i<j) R[j--]=R[i]; /*交换R[i]和R[j]*/
}
quicksort(R,s1,t1) /*对R[s1]到R[t1]*/
rectype R[ ];
int s1,t1;
{int i;
if (s1<t1) /* 只有一个记录或无记录须排序*/
{i= partition (R,s1,t1); /*对R[s1]到R[t1]做划分*/
quicksort (R,s1,i-1); /*递归处理左区间*/
quicksort (R,i+1,t1); /*递归处理右区间*/
}
}
P188 归并排序
MERGE(R,R1,low,mid,high)
rectype R[ ],R1[ ];
int low,mid,high;
{int i,j,k;
i=low;j=mid+1;k=low;
while((i<=mid)&&(i<=high))
if(R[i].key<=R[j].key)
R1[k++]=R1[i++];
else R1[k++]=R1[j++];
while (i<=mid) R1[k++]=R1[i++];
while (i<=high) R1[k++]=R1[j++];
}
P189 这两种特殊情况进行特殊处理。具体算法如下:
MERGEPASS(R,R1,length)
rectype R[],R1[];
int length;
{int i,j;
i=0;
while(i+2*length-1<n);
{MERGEPASS(R,R1,i+length-1,i+2*length-1);
i=i+2*length}
if(i+2*length-1<n-1)
MERGE(R,R1,i,i+length-1,n-1);
else
for(j=i;j<n;j++) R1[j],R[j];
}
P190 二路归并算法如下:
MERGESORT(R)
rectype R[ ];
int length;
{int length;
length=1;
while(length<n);
{MERGEPASS(R,R1,length);
length=2*length;
MERGEPASS(R1,R,length);
length=2*length;
}
}