printf("%3d",num[i]);
printf("\n");}
}
三、实验心得体会
冒泡排序主要是以“交换序列中相邻两个整数”为基础操作。
由于算法的时间复杂度考虑的只是对于问题规模n的增长率,则在难以精确计算
基本操作执行次数(或语句频度)的情况下,只需求出它关于n的增长率或阶即可。
实验二:
线性表的顺序存储结构的实现
一、实验目的:
理解线性表的顺序存储结构的特点以及相关操作
二、实验步骤
StatusInitList_Sq(SqList*L)
{
L->elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if(L->elem==NULL)
{
printf("内存分配失败!
\n");
returnOVERFLOW;
}
L->length=0;
L->listsize=LIST_INIT_SIZE;
returnOK;
}
StatusListInsert_Sq(SqList*L,inti,ElemTypee)
{
ElemType*q;
ElemType*p;
if(i<1||i>L->length+1)
returnERROR;
if(L->length>=L->listsize)
{
ElemType*newbase=(ElemType*)realloc(L->elem,sizeof(ElemType)*(L->listsize+LISTINCREMENT));
if(!
newbase)
returnOVERFLOW;
L->elem=newbase;
L->listsize+=LISTINCREMENT;
}
q=&(L->elem[i-1]);
for(p=&(L->elem[L->length-1]);p>=q;p--)*(p+1)=*p;
*q=e;
L->length++;
returnOK;
}
StatusListDelete_Sq(SqList*L,inti,ElemType*e)
{
ElemType*p,*q;
if(i<1||i>L->length)
{
printf("需要删除的位置不存在!
\n");
returnERROR;
}
p=&(L->elem[i-1]);
e=*p;
q=L->elem+L->length-1;
for(++p;p<=q;p++)*(p-1)=*p;
--L->length;
returnOK;
}
StatusListTransver_Sq(SqList*L)
{
inti;
if(L->length==0)
{
printf("\t该表为空!
\n\n");
returnERROR;
}
else
{
printf("\t该线性表为:
");
for(i=1;i<=L->length;i++)
printf("%d",L->elem[i-1]);
printf("\n\n");
}
returnOK;
}
三、实验心得体会
通过线性表的顺序表示与实现的的程序表达,可以看出:
线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。
在算法2.3中,容易实现线性表的某些操作,如随机存取第i个数据元素等。
在算法2.4中,一般情况下,删除第i(1<=i<=n)个元素时需将从第i+1至第n(共n-i)个元素依次向前移动一个位置。
从算法2.5可以看出,当在顺序存储结构的线性表中某个位置上插入或删除一个数据元素时,其时间主要耗费在移动元素上。
实验三:
有序链表合并
一、实验目的:
理解线性表的顺序存储结构以及相关操作
二、实验步骤
voidMergeList_L(LinkList&La,LinkList&Lb,LinkList&Lc)
{
LinkListpa=La->next;
LinkListpb=Lb->next;
LinkListpc=Lc=La;
while(pa&&pb)
{
if(pa->data<=pb->data)
{
pc->next=pa;pc=pa;pa=pa->next;
}
else
{
pc->next=pb;pc=pb;pb=pb->next;
}
}
pc->next=pa?
pa:
pb;
free(Lb);
}
四、实验心得体会
算法可以看出,在归并两个链表为一个链表时,,不需要另建新表的结点空间,而只需将原来两个链表中结点之间的关系解除,重新按元素值非递减的关系将所有结点链接成一个链表即可。
实验四:
有序链表的分解
一、实验目的:
理解线性表的链式存储结构的特点以及相关操作
二、实验步骤
intListInsert_L(LinkListL,inti,ElemTypee)
{
intj=0;
LinkListp=L,s;
while(p&&j{
p=p->next;
j++;
}
if(!
p||j>i-1)
{
return0;
}
s=(LinkList)malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s;
return1;
}
voidDisp_L(LinkListL)
{
LinkListp=L->next;
if(!
p)printf("thelistisnull!
");
while(p)
{
printf("%d\t",p->data);
p=p->next;
}
printf("\n");
}
voidMergeList_L(LinkList*La,LinkList*Lb,LinkList*Lc)
{
LinkListpa=(*La)->next;
LinkListpb=Lb=La;
LinkListpc=Lc;
while(pa)
{
if(pa->data%2==0)
{
pb->next=pa;pb=pa;pa=pa->next;
}
else
{
pc->next=pa;pc=pa;pa=pa->next;
}
}
pb->next=NULL;
pc->next=NULL;
}
三、实验心得体会
容易看出,算法2.9和算法2.10的时间复杂度均为O(n).这是因为,为在第i个结点之前插入一个新结点或删除第i个结点,都必须首先找到第i-1个结点,即需修改指针的结点,它是一种动态结构。
实验五:
栈的顺序存储结构的实现
一、实验目的:
理解栈的顺序存储结构的特点以及相关操作
二、实验步骤
voidInitStack(SqStack*p)
{
if(!
p)
printf("Error");
p->top=0;
}
voidPush(SqStack*p,ElemTypex)
{
if(p->top{
p->stack[p->top]=x;
p->top=p->top+1;
}
else
printf("Overflow!
\n");
}
ElemTypePop(SqStack*p)
{
ElemTypex;
if(p->top!
=0)
{
p->top=p->top-1;
x=p->stack[p->top];
printf("栈顶元素%d已经被删除!
\n",p->stack[p->top]);
return(x);
}
else
{
printf("Underflow!
\n");
return(0);
}
}
三、实验心得体会
由实验可以看出,在栈的顺序存储表示中,必须要先构造一个空栈S,在接下来的算法程序中,若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR。
接着再插入元素e为新的栈顶元素,栈满的话,则追加存储空间;若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR。
实验六:
十进制向八进制换
一、实验目的:
理解栈的顺序存储结构的特点以及相关操作
二、实验步骤
voidConversion(intN)
{
SElemTypee;
SqStacks;
InitStack(&s);
while(N){
Push(&s,N%8);
N=N/8;
}
printf("转换后的八进制数为:
");
while(StackEmpty(s)!
=1)
{
Pop(&s,&e);
printf("%d",e);
}
三、实验心得体会
这是利用栈的先进后出特性的最简单的例子。
在这给个例子中,栈操作的序列是直线式的,即先一味地入栈,然后一味地出栈。
其中,对于输入的任意一个非负十进制整数,打印输出与其等值的八进制数。
实验七:
括号匹配检验
一、实验目的:
理解栈的顺序存储结构的特点以及相关操作
二、实验步骤
voidInitStack(Stack*s)
{
s->top=0;
}
intPushStack(Stack*s,charch)
{
if(s->top==M)
return0;
s->top++;
s->element[s->top]=ch;
return1;
}
intPopStack(Stack*s,char*ch)
{
if(s->top==1)
return0;
*ch=s->element[s->top];
s->top--;
return1;
}
intGetTop(Stack*s,char*ch)
{
if(s->top!
=M)
return0;
*ch=s->element[s->top];
return1;
}
intIsEmpty(Stack*s)
{
if(s->top==M)
return1;
else{
return0;
}
}
intMatchBracket(charch1,charch2)
{
if(ch1=='('&&ch2==')'){
return1;
}
return0;
}
三、实验心得体会
可见,这个处理过程恰与栈的特点相吻合。
由此,在算法中设置一个栈,每读入一个括号,若是右括号,则或者使置于栈顶的最急迫的期待得以消解,或者是不合法的情况;若是右括号,则作为一个新的更急迫的期待圧入栈中,自然使原有的在栈中的所有未消解的期待的急迫性都降了一级。
另外,在算法的开始与结束时,栈都应该是空的。
实验八:
队列的顺序存储结构的实现
一、实验目的:
理解队列的顺序存储结构的特点以及相关操作
二、实验步骤
typedefstruct
{
Elemtypequeue[MAXNUM];
intfront;
intrear;
}sqqueue;
intinitQueue(sqqueue*q)
{
if(!
q)
returnFALSE;
q->front=q->rear=0;
returnTURE;
}
intEnQueue(sqqueue*q,Elemtypex)
{
if((q->rear+1)%MAXNUM==q->front)
returnFALSE;
q->queue[q->rear]=x;
q->rear=(q->rear+1)%MAXNUM;
returnTURE;
}
ElemtypeDeQueue(sqqueue*q)
{
Elemtypex;
if(q->front==q->rear)
return0;
x=q->queue[q->front];
q->front=(q->front+1)%MAXNUM;
returnx;
}
voiddisplay(sqqueue*q)
{
ints;
s=q->front;
if(q->front==q->rear)
printf("队列空!
\n");
else
{
printf("\n当前顺序队列的成员依次为:
");
while(s!
=q->rear)
{
printf("%d<-",q->queue[s]);
s=(s+1)%MAXNUM;
}
printf("\n");
printf("顺序队列队尾元素所在位置:
rear=%d\n",q->rear);
printf("顺序队列队头元素所在位置:
front=%d\n",q->front);
}
}
三、实验心得体会
根据算法程序可以看出,和顺序栈相类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到队列尾的元素之外,尚需附设两个指针front和rear分别指示队列头元素及队列尾元素的位置。
实验九:
队列的链式存储结构的实现
一、实验目的:
理解队列的链式存储结构的特点以及相关操作
二、实验步骤
voidcreat(Lqueue*q)
{
Qnodetype*h;
inti,n,e;
printf("输入链队列元素的个数:
");
scanf("%d",&n);
h=(Qnodetype*)malloc(sizeof(Qnodetype));
h->next=NULL;
q->front=h;
q->rear=h;
for(i=1;i<=n;i++)
{
printf("链队列第%d个元素的值为:
",i);
scanf("%d",&e);
EnQueue(q,e);}
}
voidEnQueue(Lqueue*q,inte)
{
Qnodetype*p;
p=(Qnodetype*)malloc(sizeof(Qnodetype));
p->data=e;
p->next=NULL;
q->rear->next=p;
q->rear=p;
}
ElemTypeDeQueue(Lqueue*q)
{
Qnodetype*p;
ElemTypee;
if(q->front==q->rear)
{
printf("队列为空!
");
e=0;
}
else
{
p=q->front->next;
q->front->next=p->next;
if(p->next==NULL)
q->rear=q->front;
e=p->data;
free(p);}
return(e);
}
voiddisplay(Lqueue*q)
{
Qnodetype*p;
p=q->front->next;
if(q->front==q->rear)
{printf("队列中没有元素!
");
}
else
{printf("队列元素依次为:
");
while(p!
=NULL)
{
printf("%d<-",p->data);
p=p->next;
}
}
printf("遍历队列结束!
\n");}
五、实验心得体会
通过实验可了解,在删除队列头元素时仅需修改头结点中的指针,但当队列中最后一个元素被删后,队列尾指针也丢失了,因此需对队尾指针重新赋值.
实验十:
构造二叉链表
一、实验目的:
理解二叉树的存储结构的特点以及相关操作
二、实验步骤
BiTreeCreatBiTree()
{
BiTreeT;
charch;
if((ch=getchar())=='#')
return(NULL);
else
{
T=(BiTNode*)malloc(sizeof(BiTNode));
T->data=ch;
T->lchild=CreatBiTree();
T->rchild=CreatBiTree();
return(T);
}
}
voidPreOrder(BiTNode*T)
{
if(T)
{
printf("%c",T->data);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
voidInOrder(BiTNode*T)
{
if(T)
{
InOrder(T->lchild);
printf("%c",T->data);
InOrder(T->rchild);
}
}
voidPostOrder(BiTNode*T)
{
if(T)
{
PostOrder(T->lchild);
PostOrder(T->rchild);
printf("%c",T->data);
}
}
三、实验心得体会
“遍历”是二叉树各种操作的基础,可以在遍历过程中对结点进行各种操作,如:
对于一颗已知数可求结点的双亲,求结点的孩子结点,判定结点所在层次等,反之,也可以在遍历过程中生成结点,建立二叉树的存储结构。
算法6.4是一个按先序序列建立二叉树的二叉链表的过程;首先,按先序次序输入二叉树中结点的值(一个字符),空格字符表示空树,先生成根结点,再构造左子树,最后构造右子树,这样,用递归算法构造二叉树就好了。
实验十一:
求二叉树叶子结点个数
一、实验目的:
理解二叉树的存储结构的特点以及相关操作
二、实验步骤
BiTreeCreatBiTree()
{
BiTreeT;
charch;
if((ch=getchar())=='#')
return(NULL);
else
{
T=(BiTNode*)malloc(sizeof(BiTNode));
T->data=ch;
T->lchild=CreatBiTree();
T->rchild=CreatBiTree();
return(T);
}
}
intCountLeaf(BiTreeT)
{
if(!
T)
return0;
else
if(!
T->lchild&&!
T->rchild)
return1;
else
returnCountLeaf(T->lchild)+CountLeaf(T->rchild);
}
三、实验心得体会
树中所有叶子结点的右链是线索,则右链域直接指示了结点的后继,可见,在中序线索二叉树上遍历二叉树,虽则时间复杂度亦为O(n),但常熟因子要比上节讨论的算法小,且不需要设栈。
因此,若在某程序中所有二叉树需经常遍历或查找结点在遍历所得线性序列中的前驱和后继,则应采用线索链表作存储结构。
实验十二:
哈夫曼编码的实现
一、实验目的:
理解和实现哈夫曼算法
二、实验步骤
voidCrtHuffmanTree(HuffmanTree*ht,int*w,intn)
{
intm,i,s1,s2;
m=2*n-1;
*ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
for(i=1;i<=n;i++)
{
(*ht)[i].weight=w[i];
(*ht)[i].LChild=0;
(*ht)[i].parent=0;
(*ht)[i].RChild=0;
}
for(i=n+1;i<=m;i++)
{
(*ht)[i].weight=0;
(*ht)[i].LChild=0;
(*ht)[i].parent=0;
(*ht)[i].RChild=0;
}
printf("\nhuffmanTree:
\n");
for(i=n+1;i<=m;i++)
{
Select(ht,i-1,&s1,&s2);
(*ht)[s1].parent=i;
(*ht)[s2].parent=i;
(*ht)[i].LChild=s1;
(*ht)[i].RChild=s2;
(*ht)[i].weight=(*ht)[s1].weight+(*ht)[s2].weight;
printf("%2d,%2d,%2d,%2d\n",(*ht)[i].weight,(*ht)[i].parent,(*ht)[i].LChild,(*ht)[i].RChild);
}
printf("\n");
}
voidCrtHuffmanCode(HuffmanTree*ht,HuffmanCode*hc,intn)
{
char*cd;
inti,start,p;
unsignedintc;
hc=(HuffmanCode*)malloc((n+1)*sizeof(char*));
cd=(char*)malloc(n*sizeof(char));
cd[n-1]='\0';
for(i=1;i<=n;i++)
{
start=n-1;
for(c=i,p=(*ht)[i].parent;p!
=0;c=p,p=(*ht)[p].parent)
if((*ht)[p].LChild==c)
cd[--start]='0';
else
cd[--start]='1';
hc[i]=(char*)malloc((n-st