关于单链表,二叉树,图,查找和排序的软件编程
课程名称:计算机软件
使用软件:devcpp
注意:这里列出了关于单链表,二叉树,图,查找和排序的编程,全部程序由博主一人编写,会有瑕疵,谨慎使用。
1.单链表
要求:(1)建立单向链表,表长任意;
(2)可交互输出单链表中的内容;
(3)编写算法计算出自己所建单链表的长度并输出;
(4)删除自己所建单链表中的第K个结点,并将剩余结点输出;
(5)将单链表倒排,输出结果。
程序:
#include <stdio.h>
#include <stdlib.h>
//定义链表中的节点
struct node
{ unsigned char data;//链表中的数据
struct node * next;//指向下一节点的指针
};
//变量定义
struct node *p,*p1,*p2,*head;
//函数声明
void ListCreate();
void ListTraverse();
void ListLength();
int ListDelete();
int ListReverse();
//主函数
int main()
{
ListCreate(); //单向链表的建立
ListTraverse(); //单向链表的输出
ListLength(); //单向链表长度计算
ListDelete(); //单向链表结点的删除
ListReverse(); //单链表的倒排
}
//单向链表的建立
void ListCreate()
{
head=p=(struct node * )malloc(sizeof(struct node));
printf("请输入链表数据元素值(0为结束标志,中间不能用任何符号):\n");
scanf("%c",&p->data);//头结点的数据成员
while(p->data!='0')//给出0结束条件,退出循环
{
p1=p;
p=(struct node * )malloc(sizeof(struct node));
scanf("%c",&p->data);//中间结点数据成员
p1->next=p;//中间结点的指针成员值
}
p->next=NULL;//尾结点的指针成员值
}
//单向链表的输出
void ListTraverse()
{
p=head;
printf("\n链表数据成员是:");
while(p->next!=NULL)
{
printf("%c ",p->data); //输出成员数据
p=p->next;
}
}
//单向链表长度计算
void ListLength()
{
p2=head->next;
int j=1; //j用来存放链表的长度
while((p2->data)-48)
{
p2=p2->next;
j++;
}
printf("\n链表长度是: %d",j);
}
//单向链表结点的删除
int ListDelete()
{
p2 = head;
int j = 1,M,K;
printf("\n要删除第几个节点: ");
scanf("%d",&K);
if ( j > (K-1)) //删除头节点
{
struct node *p3;
p3=p2;
p2=p3->next;
}
else //删除其它节点
{
while ((p2->next)-48 && j < (K-1))
{
p2 = p2->next;
++j;
}
if (p2->next == NULL )
{
printf("Position Error\n");
return 0;
}
struct node *temp = p2->next; //执行删除操作
p2->next = temp->next;
}
p=head;
printf("删除后的链表数据成员是:");
while(p->next!=NULL)
{
printf("%c ",p->data); //输出成员数据
p=p->next;
}
}
//单链表的倒排
int ListReverse()
{
struct node *h,*h1,*h2;
h=head;
h1=h;
h=NULL;
while(h1->next!=NULL) //通过循环使h从最后一个元素依次向前
{
h2 = h1->next;
h1->next = h;
h = h1;
h1 = h2;
}
printf("\n倒排后的链表数据成员是:");
while(h!=NULL) //输出数据元素
{
printf("%c ",h->data);
h=h->next;
}
}
难点:单链表的倒排,这里有两种方法实现
1)逆序单链表的循环算法:
1 LINK_NODE *ReverseLink(LINK_NODE *head)
2 {
3 LINK_NODE *next;
4 LINK_NODE *prev = NULL;
5
6 while(head != NULL)
7 {
8 next = head->next;
9 head->next = prev;
10 prev = head;
11 head = next;
12 }
13
14 return prev;
15 }
2)逆序单链表的递归算法:
1 LINK_NODE *ReverseLink2(LINK_NODE *head)
2 {
3 LINK_NODE *newHead;
4
5 if((head == NULL) || (head->next == NULL))
6 return head;
7
8 newHead = ReverseLink2(head->next); /*递归部分*/
9 head->next->next = head; /*回朔部分*/
10 head->next = NULL;
11
12 return newHead;
13 }
循环还是递归?这是个问题。当面对一个问题的时候,不能一概认为哪种算法好,哪种不好,而是要根据问题的类型和规模作出选择。对于线性数据结构,比较适合用迭代循环方法,而对于树状数据结构,比如二叉树,递归方法则非常简洁优雅。原文链接:https://blog.csdn.net/lycnjupt/article/details/47103433
如果想了解关于逆序单链表的其它实现方法,可以查看链接:
http://blog.sina.com.cn/s/blog_68e4d2910100tc0i.html
2.二叉树
要求:(1)动态交互建立二叉树,结点个数任意;
(2)分别用DLR,LDR,LRD三种方式对二叉树进行遍历,并输出结果;
(3)计算二叉树中的结点个数并输出;
(4)计算二叉树的深度并输出。
我自己的程序:
#include <stdio.h>
#include <stdlib.h>
//节点声明,数据域、左指针、右指针
typedef struct BiTNode
{
int data;//二叉树数据元素
struct BiTNode *Left,*Right;//二叉树左右指针
}BiTNode,*BiTree;
//函数声明
int CreateBiTree(BiTNode **T);
void DLR_BiTree(BiTNode *T);
void LDR_BiTree(BiTNode *T);
void LRD_BiTree(BiTNode *T);
int BiTreeCount(BiTNode *T);
int BiTreeDeep(BiTNode *T);
//主函数
int main()
{
BiTree T;
int depth,Count = 0;
printf("请输入第一个节点的值(0表示没有该节点): ");
CreateBiTree(&T);//二叉树建立
printf("\n");
printf("先序遍历二叉树:");
DLR_BiTree(T);//二叉树先序遍历
printf("\n");
printf("中序遍历二叉树:");
LDR_BiTree(T);//二叉树中序遍历
printf("\n");
printf("后序遍历二叉树:");
LRD_BiTree(T);//二叉树后序遍历
printf("\n");
Count = BiTreeCount(T);//求二叉树结点个数
printf("二叉树结点个数:%d\n",Count);
depth = BiTreeDeep(T);//求二叉树深度
printf("二叉树的深度为:%d\n",depth);
}
//先序创建二叉树
int CreateBiTree(BiTNode **T)
{
int ch;
scanf("%d",&ch);//给二叉树第一个节点赋值
if (ch == 0)
{
*T = NULL; //输入为0表示没有该节点
return 0;
}
else
{
*T = (BiTNode *)malloc(sizeof(BiTNode)); //给二叉树节点分配内存
if (T == NULL)
{
printf("failed\n");
return 0;
}
else
{
(*T)->data = ch;
printf("输入%d的左子节点:",ch);
CreateBiTree(&((*T)->Left)); //递归给二叉树左节点赋值
printf("输入%d的右子节点:",ch);
CreateBiTree((&(*T)->Right)); //递归给二叉树右节点赋值
}
}
return 1;
}
//二叉树先序遍历
void DLR_BiTree(BiTNode *T)
{
if( T == NULL) return;//递归调用的结束条件
printf("%d",T->data);//访问节点的数据域
DLR_BiTree(T->Left);//先序递归遍历左子树
DLR_BiTree(T->Right);//先序递归遍历右子树
}
//二叉树中序遍历
void LDR_BiTree(BiTNode *T)
{
if(T==NULL) return;//递归调用的结束条件
LDR_BiTree(T->Left);//中序递归遍历左子树
printf("%d",T->data);//访问节点的数据域
LDR_BiTree(T->Right);//中序递归遍历右子树
}
//二叉树后序遍历
void LRD_BiTree(BiTNode *T)
{
if(T==NULL) return;//递归调用的结束条件
LRD_BiTree(T->Left);//后序递归遍历左子树
LRD_BiTree(T->Right);//后序递归遍历右子树
printf("%d",T->data);//访问节点的数据域
}
//求二叉树结点个数
int BiTreeCount(BiTNode *T)
{
if(T==NULL)
return 0;//空二叉树结点数为0
else
return BiTreeCount(T->Left)+BiTreeCount(T->Right)+1;//左右子树结点总数加1
}
//求二叉树深度
int BiTreeDeep(BiTNode *T)
{
int deep = 0;
if (T != NULL)
{
int leftdeep = BiTreeDeep(T->Left);//递归得到左子树深度
int rightdeep = BiTreeDeep(T->Right);//递归得到右子树深度
deep = leftdeep >= rightdeep?leftdeep+1:rightdeep+1;//比较得到二叉树深度
}
return deep;
}
3.图
要求:(1)根据教材上算法,完成图的深度和广度优先遍历,要求任意给定起始点,输出结果。
(2)根据教材上算法,完成图的单元最短路径的算法,要求任意给定源点,输出结果。
程序:
#include <stdio.h> #include <stdlib.h> #define MAXVEX 100 //最大顶点数 #define INFINITY 65535 //用65535来代表无穷大 //定义访问标记 int visited[MAXVEX]={0}; //定义图结构体 typedef struct { char vexs[MAXVEX]; //顶点表 int arc[MAXVEX][MAXVEX]; //邻接矩阵,可看作边 int numVertexes, numEdges; //图中当前的顶点数和边数 }Graph; //辅助数组中的元素定义 typedef struct { int distance; int path[MAXVEX]; }ArrayNode; //函数声明 void CreateGraph(Graph *g); void DFS(Graph g,int v); void BFS(Graph g,int v); void SHORT(Graph *g,int from,int to); void SHORT(Graph *g,int from,int to); //主函数 int main() { Graph g; int i,from,to; printf("t为1-4,分别表示无向图、有向图、带权无向图、带权有向图\n"); CreateGraph(&g);//创建图 printf("\n输入遍历起点: "); scanf("%d",&i); printf("\n深度优先搜索遍历:"); DFS(g,i);//深度优先遍历函数 printf("NULL\n"); printf("广度优先搜索遍历:"); BFS(g,i);//广度优先遍历函数 printf("NULL\n"); printf("\nDijkstra算法单元最短路径:"); printf("\n请输入起点和终点(中间用空格):"); scanf("%d %d",&from,&to); SHORT(&g,from,to);//Dijkstra算法单元最短路径函数 } //创建图 void CreateGraph(Graph *g) { int i,j,k,w,t; printf("输入顶点数,边数和t(中间用空格):"); scanf("%d %d %d", &(g->numVertexes), &(g->numEdges),&t); printf("\n"); for(i=1;i<=g->numVertexes;i++)//通过循环输入顶点信息 { getchar(); printf("输入第%d顶点信息vexs[%d]=",i,i); scanf("%c",&(g->vexs[i])); } printf("\n"); for(i=1;i<=g->numVertexes;i++) for(j=1;j<=g->numVertexes;j++) if (t>2) g->arc[i][j] = INFINITY;//区别是否带权值 else g->arc[i][j]=0; for(k=1;k<=g->numEdges;k++)//通过循环输入边的信息 { printf("输入有联系的两个顶点(中间用空格):"); scanf("%d %d",&i,&j); if(i>g->numVertexes ||j>g->numVertexes) exit(0); if(t>2) { printf("输入权值:"); scanf("%d",&w); g->arc[i][j]=w; if(t==3) g->arc[j][i]=w; } else { g->arc[i][j]=1; if (t==1) g->arc[j][i]=1; } } printf("\n"); printf("输出邻接矩阵:\n"); for(i=1;i<=g->numVertexes ;i++) { for(j=1;j<=g->numVertexes ;j++) { printf("%8d",g->arc[i][j]); //输出邻接矩阵 /*if(t>2&&g->arc[i][j]==65535) g->arc[i][j]=0; else if(t>2&&g->arc[i][j]!=65535) g->arc[i][j]=1; */ } printf("\n"); } } //深度优先遍历 void DFS(Graph g,int v) { int j; printf("%d->",v); //输出访问顶点 visited[v]=1; //全局数组访问标记置1表示已经访问 for(j=1; j<=g.numVertexes; j++) if ((g.arc[v][j]!=0)&&(g.arc[v][j]!=65535)&&(!visited[j])) DFS (g,j);//递归访问非0非无穷顶点 } //广度优先遍历 void BFS(Graph g,int v) { int q[g.numVertexes+1] ; int i,f,r,j ; for(i=0;i<g.numVertexes;i++) visited[i]=0; //重置访问标记 f=r=0 ; printf("%d->",v);//输出第一个顶点 visited[v]=1 ;//标记已访问 r++; q[r]=v; while (f<r) { f++; v=q[f]; for (j=1; j<=g.numVertexes; j++) //广度优先遍历依次访问与上一顶点有联系的点 { if ((g.arc[v][j]!=0)&&(g.arc[v][j]!=65535)&&(!visited[j])) { printf("%d->",j);//输出访问顶点 visited[j]=1 ; r++; q[r]=j ; } } } } //单元最短路径算法 void SHORT(Graph *g,int from,int to) { int i,j,index=-1; int n=1;//记录已经求出的两个点之间的最短距离的个数 ArrayNode shortestPath[MAXVEX]; int flag[MAXVEX]={0};//标记,为1表示到这个顶点的最短距离已求出 //1.求from到各个顶点的直接距离,即初始化shortestPath数组 for(i=1;i<=g->numVertexes;i++) { if(from==i) { shortestPath[i].distance=0; shortestPath[i].path[0]=i; flag[from]=1; } else if(g->arc[from][i]>0) { shortestPath[i].path[0]=from; shortestPath[i].path[1]=i; shortestPath[i].distance=g->arc[from][i]; } else shortestPath[i].distance=INFINITY; } //2.每次求一个最短路径 while(n<=g->numVertexes) { //选择shortestPath中距离最小的,求出from到这个顶点的最短路径 index=-1; for(i=1;i<=g->numVertexes;i++) { if(i==from) continue; if(flag[i]==0 && index==-1 && shortestPath[i].distance!=INFINITY) index=i; if(flag[i]==0 && index!=-1 && shortestPath[i].distance<shortestPath[index].distance) index=i; } flag[index]=1; //修改到各个顶点的最短路径 for(i=1;i<=g->numVertexes;i++) { if(i==from) continue; if(g->arc[index][i]>0 && g->arc[index][i]+shortestPath[index].distance<shortestPath[i].distance) { shortestPath[i].distance=g->arc[index][i]+shortestPath[index].distance; //修改路径 j=0; while(1) { shortestPath[i].path[j]=shortestPath[index].path[j]; if(shortestPath[index].path[j]==index) break; j++; } shortestPath[i].path[j+1]=i; } } n++; } //输出from到to的最短路径及长度 if(shortestPath[to].distance==INFINITY){ printf("%d到%d没有路径\n",from,to); return; } printf("%d到%d的最短路径长度是:%d\n",from,to,shortestPath[to].distance); printf("经过的顶点: "); i=0; while(1){ printf("%-3d",shortestPath[to].path[i]); if(shortestPath[to].path[i]==to) break; i++; } printf("\n"); }
4.查找和排序
要求:(1)任意给定无序序列,用对半检索法,交互检索任意给定的关键字KEY;
(2)任意给定无序序列,用快速排序法对序列进行排序,并统计交换次数;
(3)任意给定无序序列,用冒泡排序法对序列进行排序,并统计交换次数和排序趟数。
程序:
#include "stdio.h" #define N 6//序列长度(可修改) //函数声明 int halfSort(int *b,int n); void quickSort(int *b,int l,int r); void bubbleSort(int *bb,int r); //全局变量定义 int o,p,k; int KEY; //检索的关键字 //主函数 int main() { int i,j,q; int a[100],aa[100],aaa[100];//以数组方式定义序列 printf("Hello World!\n"); printf("\n1.请输入任意序列(用回车隔开)\n"); for(i=1;i<=N;i++) scanf("%d",&a[i]);//输入无序序列 quickSort(a,1,N);//先排序再进行对半检索 printf("排序后序列为:"); for(j=1;j<=N;j++) printf("%d ",a[j]);//输出有序序列 printf("\n请输入需要检索的关键字KEY:"); scanf("%d ",&KEY); q=halfSort(a,N);//对半检索函数调用 printf("对半检索-关键字位置为:%d\n",q); printf("\n2.请输入任意序列(用回车隔开)\n"); for(i=0;i<N;i++) scanf("%d",&aa[i]);//输入无序序列 quickSort(aa,0,N-1);//快速排序函数调用 printf("快速排序后序列为:"); for(j=0;j<N;j++) printf("%d ",aa[j]);//输出有序序列 printf("\n交换次数为:%d\n",k); printf("\n3.请输入任意序列(用回车隔开)\n"); for(i=0;i<N;i++) scanf("%d",&aaa[i]);//输入无序序列 bubbleSort(aaa,N); printf("冒泡排序后序列为:");//冒泡排序函数调用 for(j=0;j<N;j++) printf("%d ",aaa[j]);//输出有序序列 printf("\n交换次数为:%d\n",o); printf("排序趟数为:%d\n",p); return 0; } //对半检索函数 int halfSort(int *b,int n) { int high,mid,low; int rs=0; low=1;high=n;//初始状态 while(low<=high)//判断查找是否结束 { mid=(low+high)/2; if(KEY<b[mid]) high=mid-1;//关键字在前半区 else if(KEY>b[mid]) low=mid+1;//关键字在后半区 else {rs=mid;break;} } return rs; } //快速排序函数 void quickSort(int *bb,int l,int r) { int m,n; int temp; if(l>=r) return;//只有一个记录或无记录,无须排序 m=l; n=r; temp=bb[m]; while(m!=n)//寻找temp的最终位置 { while((bb[n]>=temp)&&(n>m)) n--;//从右向左扫描,查找第一个小于temp的记录 if(m<n) {bb[m++]=bb[n];k++;} while((bb[m]<=temp)&&(n>m)) m++;//从左向右扫描,查找第一个大于temp的记录 if(m<n) {bb[n--]=bb[m];k++;} } bb[m]=temp;//找到temp的最终位置 quickSort(bb,l,m-1);//递归处理左区间 quickSort(bb,m+1,r);//递归处理右区间 } //冒泡排序函数 void bubbleSort(int *bbb,int r) { int m,n,noswap; int temp; for(m=0;m<(r-1);m++)//外循环,做N-1次起泡 { noswap=1; for(n=0;n<(r-m-1);n++)//内循环,置交换标志 if(bbb[n+1]<bbb[n])//比较 { temp=bbb[n]; bbb[n]=bbb[n+1]; bbb[n+1]=temp;//交换 o++; noswap=0; } if(noswap) break;//本趟起泡未发生记录交换,算法结束 p++; } }