if(!
p||j>i-1)returnERROR;
s=(LinkList)malloc(sizeof(LNode));
s→data=e;s→next=p→next;
p→next=s;
returnOK;
}//LinkList_L
}
4、删除单链表中的第6个数据元素和第8个数据元素,给出删除成功或失败的信息,并输出单链表中的各元素值。
单链表的删除操作如下:
StatusListDelete_L(LinkListL,inti,ElemType&e){
//删除以L为头指针(带头结点)的单链表中第i个结点
p=L;j=0;
while(p->next&&jnext;++j;}
//寻找第i个结点,并令p指向其前趋
if(!
(p->next)||j>i-1)returnERROR;//删除位置不合理
q=p->next;p->next=q->next;//删除并释放结点
e=q->data;free(q);
returnOK;
}//ListDelete_L
5、取单链表中的第5个数据元素和第7个数据元素
StatusGetElem_L(LinkListL,inti,ElemType&e){
//L为带头结点的单链表的头指针。
//当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
p=L→next;j=1;//初始化
while(p&&j
p=p→next;++j;
}
if(!
p||j>i)returnERROR;//第i个元素不存在
elsee=p→data; //取第i个元素
returnOK;
}//GetElem_L
五、问题讨论
1、单链表具有什么优缺点?
2、单链表的定义与顺序表的定义有什么区别?
3、逆序创建单链表有什么好处?
4、为什么单链表中取元素、插入和删除操作在开始不判断给定位置i的合法性?
5、当给定位置大于单链表长度时,取元素、插入和删除操作分别是如何执行的?
6、如何改进单链表的定义,使其可以在操作前判断判断给定位置i的合法性?
六、实验报告内容
1、实验目的
2、实验内容和具体要求
3、完成情况和实验记录,实验记录为实验过程中遇到的问题及解决方法
4、程序清单
5、所输入的数据及相应的运行结果
6、问题回答
7、实验心得
实验二、二叉树的遍历
一、实验目的
1、掌握二叉树的特点及其存储方式。
2、掌握二叉树的创建。
3、掌握二叉树前序、中序、后序遍历的基本方法及应用。
二、实验内容
1、用前序方法建立一棵二叉树。
2、编写前序遍历二叉树的程序。
3、编写中序遍历二叉树的程序。
4、编写后序遍历二叉树的程序。
5、编写统计二叉树叶子结点个数的程序
三、实验环境
TC或VC++
四、实验步骤
1、二叉树的二叉链表存储类型定义
typedefstructBiTNode
{datatypedata;
structBiTNode*lchild,*rchild;
}BiTNode,*BiTree;
2、建立下图所示的二叉树
以字符串的形式“根左子树右子树”定义一棵二叉树时,创建二叉树的算法如下:
StatusCreateBiTree(BiTree&T){
scanf(&ch);
if(ch=='')T=NULL;
else{
if(!
(T=newBiTNode))
exit(OVERFLOW);
T->data=ch;//生成根结点
CreateBiTree(T->lchild);//构造左子树
CreateBiTree(T->rchild);//构造右子树
}
returnOK;}//CreateBiTree
3、编程实现以上二叉树的前序、中序和后序遍历操作,输出遍历序列
(1)先序遍历二叉树的递归算法如下:
voidPreorder(BiTreeT,void(*visit)(TElemType&e))
{//先序遍历二叉树
if(T){
visit(T->data);//访问结点
Preorder(T->lchild,visit);//遍历左子树
Preorder(T->rchild,visit);//遍历右子树
}
}
(2)中序遍历二叉树的递归算法如下:
voidInorder(BiTreeT,void(*visit)(TElemType&e))
{//中序遍历二叉树
if(T){
Inorder(T->lchild,visit);//遍历左子树
visit(T->data);//访问结点
Inorder(T->rchild,visit);//遍历右子树
}
}
(3)后序遍历二叉树的递归算法如下:
voidPostorder(BiTreeT,void(*visit)(TElemType&e))
{//后序遍历二叉树
if(T){
Postorder(T->lchild,visit);//遍历左子树
Postorder(T->rchild,visit);//遍历右子树
visit(T->data);//访问结点
}
}
(4)先序遍历二叉树的非递归算法如下:
StatusPreOrderTraverse(BiTreeT,Status(*visit)(TElemType&e)){
InitStack(S);p=T;
While(p||!
StackEmpty(S)){
if(p){if(!
visit(p->data))returnERROR;
Push(S,p);p=p->lchild;}
else{
Pop(S,p);
p=p->rchild;
}//else
}//while
returnOK;
}
(5)中序遍历二叉树的非递归算法如下:
StatusInOrderTraverse(BiTreeT,Status(*visit)(TElemType&e)){
InitStack(S);p=T;
While(p||!
StackEmpty(S)){
if(p){Push(S,p);p=p->lchild;}
else{
Pop(S,p);
if(!
visit(p->data))returnERROR;
p=p->rchild;
}//else
}//while
returnOK;
}
4、统计以上二叉树中叶子结点的个数
算法基本思想:
先序(或中序或后序)遍历二叉树,在遍历过程中查找叶子结点,并计数。
由此,需在遍历算法中增添一个“计数”的参数,并将算法中“访问结点”的操作改为:
若是叶子,则计数器增1。
算法如下:
voidCountLeaf(BiTreeT,int&count){
if(T){
if((!
T->lchild)&&(!
T->rchild))
count++;//对叶子结点计数
CountLeaf(T->lchild,count);
CountLeaf(T->rchild,count);
}//if
}//CountLeaf
五、问题讨论
1、先序、中序、后序遍历二叉树的区别?
2、在先序、中序非递归算法中为什么使用栈?
能不能借助其它数据结构来实现?
六、实验报告内容
1、实验目的
2、实验内容和具体要求
3、完成情况和实验记录,实验记录为实验过程中遇到的问题及解决方法
4、程序清单
5、所输入的数据及相应的运行结果
6、问题回答
7、实验心得
实验三、折半查找和二叉排序树
一、实验目的
1、掌握查找的特点。
2、掌握折半查找的基本思想及其算法。
3、熟悉二叉排序树的特点,掌握二叉排序树的插入、删除操作。
二、实验内容
1、设有关键字序列k={5,14,18,21,23,29,31,35},查找key=21和key=25的数据元素。
2、根据关键字序列{45、24、53、12、37、93}构造二叉排序树,并完成插入13删除关键字53和24的操作。
三、实验环境
TC或VC++
四、实验步骤
1、折半查找
(1)从键盘输入上述8个整数5,14,18,21,23,29,31,35,存放在数组bub[8]中,并输出其值。
(2)从键盘输入21,查找是否存在该数据元素,若存在,则输出该数据元素在表中的位置,否则给出查找失败的信息。
(3)从键盘输入25,查找是否存在该数据元素,若存在,则输出该数据元素在表中位置,否则给出查找失败的信息。
折半查找算法如下:
intSearch_Bin(SSTableST,KeyTypekval){
low=1;high=ST.length;//置区间初值
while(low<=high){
mid=(low+high)/2;
if(kval==ST.elem[mid].key)
returnmid;//找到待查元素
elseif(kvalhigh=mid-1;//继续在前半区间进行查找
elselow=mid+1;//继续在后半区间进行查找
}
return0;//顺序表中不存在待查元素
}//Search_Bin
2、二叉排序树
(1)二叉排序树结点定义
typedefstructBiTNode{//结点结构
TElemTypedata;
structBiTNode*lchild,*rchild;//左右孩子指针
}BiTNode,*BiTree;
(2)从键盘上输入六个整数45、24、53、12、37、9构造二叉排序树
(3)输出其中序遍历结果。
(4)插入数据元素13,输出其中序遍历结果。
在二叉排序树上插入结点的算法如下:
StatusInsertBST(BiTree&T,ElemTypee){
if(!
SearchBST(T,e.key,NULL,p)){
s=newBiTNode;//为新结点分配空间
s->data=e;
s->lchild=s->rchild=NULL;
if(!
p)T=s;//插入s为新的根结点
elseif(LT(e.key,p->data.key))
p->lchild=s;//插入*s为*p的左孩子
elsep->rchild=s;//插入*s为*p的右孩子
returnTRUE;//插入成功
}
elsereturnFALSE;
}//InsertBST
(5)删除数据元素24和53,输出其中序遍历结果。
在二叉排序树上删除结点的算法如下:
VoidDelete(BSTreebst,keytypex){
BSTreef=NULL,p=bst;
while(p&&p->key!
=x)
if(p->key>x){f=p;p=p->lchild;}
else{f=p;p=p->rchild;}
if(p==NULL){
printf(“无关键字x\n”);exit(0);}
if(p->lchild=NULL)
if(f->lchild==p)f->lchild=p->rchild;
elsef->rchild=p->rchild;
else{q=p;s=p->lchild;
while(s->rchild!
=NULL){q=s;s=s->rchild;}
if(q==p)p->lchild=s->lchild;
elseq->rchild=s->lchild;
free(s);}
}
五、问题讨论
1、折半查找递归算法该怎么描述?
2、二叉排序树中序遍历结果有什么特点?
3、在二叉树排序树中插入一个新结点,总是插入到叶结点下面吗?
4、在任意一棵非空二叉排序树中,删除某结点后又将其插入,则所得二排序叉树与原二排序叉树相同吗?
六、实验报告内容
1、实验目的
2、实验内容和具体要求
3、完成情况和实验记录,实验记录为实验过程中遇到的问题及解决方法
4、程序清单
5、所输入的数据及相应的运行结果
6、问题回答
7、实验心得
实验四、内部排序
一、实验目的
1、掌握排序的有关概念和特点。
2、熟练掌握直接插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序、归并排序、基数排序等算法的基本思想。
。
3、关键字序列有序与无序,对于不同的排序方法有不同的影响,通过该实验进一步加深理解。
二、实验内容
设有关键字序列k={12,45,21,12,30,2,68,33},试用各种排序算法进行排序。
三、实验环境
TC或VC++
四、实验步骤
1、从键盘输入上述8个整数,存放在数组quick[8]中,并输出值。
2、输出各种排序算法每一趟排序的结果,观察关键字次序的变化。
(1)直接插入排序算法如下:
voidInsertionSort(SqList&L){
//对顺序表L作直接插入排序。
for(i=2;i<=L.length;++i)
if(L.r[i].keyL.r[0]=L.r[i];//复制为监视哨
for(j=i-1;L.r[0].keyL.r[j+1]=L.r[j];//记录后移
L.r[j+1]=L.r[0];//插入到正确位置
}
}//InsertSort
(2)希尔排序算法如下:
voidShellInsert(SqList&L,intdk){
for(i=dk+1;i<=n;++i)
if(L.r[i].keyL.r[0]=L.r[i];//暂存在R[0]
for(j=i-dk;j>0&&(L.r[0].keyj-=dk)
L.r[j+dk]=L.r[j];//记录后移,查找插入位置
L.r[j+dk]=L.r[0];//插入
}//if
}//ShellInsert
voidShellSort(SqList&L,intdlta[],intt)
{//增量为dlta[]的希尔排序
for(k=0;kShellInsert(L,dlta[k]);
//一趟增量为dlta[k]的插入排序
}//ShellSort
(3)冒泡排序算法如下:
voidBubbleSort(ElemR[],intn){
i=n;
while(i>1){
lastExchangeIndex=1;
for(j=1;j
if(R[j+1].keySwap(R[j],R[j+1]);
lastExchangeIndex=j;//记下进行交换的记录位置
}//if
i=lastExchangeIndex;
}//while
}//BubbleSort
(4)快速排序算法如下:
intPartition(RedTypeR[],intlow,inthigh){
R[0]=R[low];pivotkey=R[low].key;//枢轴
while(lowwhile(low=pivotkey)
--high;//从右向左搜索
R[low]=R[high];
while(low++low;//从左向右搜索
R[high]=R[low];
}
R[low]=R[0];returnlow;
}//Partition
voidQSort(RedType&R[],ints,intt){
//对记录序列R[s..t]进行快速排序
if(spivotloc=Partition(R,s,t);//对R[s..t]进行一次划分
QSort(R,s,pivotloc-1);
QSort(R,pivotloc+1,t);
}
}//QSort
(5)简单选择排序的算法描述如下:
voidSelectSort(ElemR[],intn){
//对记录序列R[1..n]作简单选择排序。
for(i=1;ij=SelectMinKey(R,i);//在R[i..n]中选择关键字最小的记录
if(i!
=j)R[i]←→R[j];//与第i个记录交换
}
}//SelectSort
(6)堆排序算法描述如下:
voidHeapSort(HeapType&H){
//对顺序表H进行堆排序
for(i=H.length/2;i>0;--i)
HeapAdjust(H.r,i,H.length);//建大顶堆
for(i=H.length;i>1;--i){
H.r[1]←→H.r[i];
HeapAdjust(H.r,1,i-1);//对H.r[1]进行筛选
}
}//HeapSort
voidHeapAdjust(RcdType&R[],ints,intm)
{
rc=R[s];//暂存R[s]
for(j=2*s;j<=m;j*=2){//j初值指向左孩子
if(jif(rc.key>=R[j].key)break;
R[s]=R[j];s=j;
}
R[s]=rc;
}//HeapAdjust
(7)归并排序算法描述如下:
voidMsort(RcdTypeSR[],
RcdType&TR1[],ints,intt){
//将SR[s..t]归并排序为TR1[s..t]
if(s==t)TR1[s]=SR[s];
else
{
m=(s+t)/2;
Msort(SR,TR2,s,m);//递归地将SR[s..m]归并为有序的TR2[s..m]
Msort(SR,TR2,m+1,t);
Merge(TR2,TR1,s,m,t);
}
}//Msort
3、如果上述8个整数按照升序输入,即k1={2,12,12,21,30,33,45,68},输出各种排序算法每一趟排序的结果,观察关键字次序的变化。
4、如果上述