数据结构-排序线性表实现学生管理系统
- 1. 树的定义
由n(n>=0)个结点的有限集。n=0表示空树。
n>1 满足:
(1) 有且只有一个根结点。
(2) 其余结点分成互不相交的m个子集T1、T2、...、Tm,每个集合又都是一颗树。
注意:1)树可以是空树。
1)树的定义具有递归性 (树中有树)。
- 2. 树的术语
(1) 根:即根结点(没有前驱)
(2) 叶子:即终端结点(没有后继)
(3) 孩子:即下一层那个结点(直接后继)
(4) 双亲:即下层结点的子树的根(直接前驱)
(5) 兄弟:同一双亲下的同层结点(孩子之间互称兄弟)
(6) 堂兄弟:即双亲位于同一层的结点(但并非同一双亲)
(7) 祖先:即从根到该结点所经分支的所有结点
(8) 子孙:即该结点下层子树中的任一结点
(9) 森林:指m棵不相交的树的集合
(10) 有序树:结点各子树从左至右有序,不能互换
(11) 无序树:结点各子树可互换位置。
(12) 结点:即树的数据元素
(13) 结点的度:该结点挂接的子树数
(14) 树的度:所有结点度中的最大值
(15) 结点的层次:从根到该结点的层数(根结点算第一层)
(16) 树的高度(深度):指所有结点中最大的层数
(17) 分支结点:即度不为0的结点(也称为内部结点)
(18) 终端结点:即度为0的结点,即叶子
- 3. 二叉树的定义
二叉树是n(n≥0)个节点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两颗互不相交的、分别称为根结点的左子树和右子树的二叉树组成。
- 4. 特殊的二叉树
(1) 斜树
(2) 满二叉树
(3) 完全二叉树
- 5. 二叉树的性质
性质1:在二叉树的第i层上至多有2i-1个结点(i≥1)。
性质2:深度为k的二叉树至多有2k-1个结点(k≥1)
性质3:对任何一棵二叉树T,如果其终端结点数(即叶子结点数)为n0,度为2的结点数为n2,则n0=n2+1。
性质4:具有n个结点的完全二叉树的深度为 log2n + 1( x 表示不大于x的最大整数)。
性质5: 如果对一棵有n个结点的完全二叉树(其深度为 log2n + 1)的结点按层序编号(从第一层到第 log2n + 1层,每层从左到右),对任一结点i(1≤i≤n)有:
(1)如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则双亲是结点 i/2 。
(2)如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩是结点2i。
(3)如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1。
- 6. 二叉树的遍历
(1) 先序遍历: 根结点 左子树 右子树
(2) 中序遍历: 左子树 根结点 右子树
(3) 后序遍历: 左子树 右子树 根结点
根据先序序列和中序序列可以恢复二叉树。
根据后序序列和中序序列可以恢复二叉树。
- 7. 赫夫曼树:赫夫曼(Huffman)树,又称最优树,是一类带权路径长度最短的树。
#include "stdio.h" #define MAX 100 struct student { int id; char name[20]; char sex[10]; char home[50]; char tel[15]; }; struct slist { struct student a[MAX]; int len; }; void add(struct slist *s,int n) { int i,j,id,flag=0; for(i=1;i<=n;i++) { printf("第%d个学生:\n",i); la: printf("\t\t请输入学生编号:"); scanf("%d",&id); flag=0; for(j=0;j<s->len;j++) { if(s->a[j].id==id) { flag=1; printf("编号已经存在,请重新输入。\n"); goto la; } } if(flag==0) { s->a[s->len].id=id; printf("\t\t请输入学生姓名:"); scanf("%s",s->a[s->len].name); printf("\t\t请输入学生性别:"); scanf("%s",s->a[s->len].sex); printf("\t\t请输入学生籍贯:"); scanf("%s",s->a[s->len].home); printf("\t\t请输入学生电话:"); scanf("%s",s->a[s->len].tel); s->len++; } } } void output(struct slist *s) { int i; for(i=0;i<s->len;i++) { printf("第%d个学生:\n",i+1); printf("\t\t学生学号:%d\n",s->a[i].id); printf("\t\t学生姓名:%s\n",s->a[i].name); printf("\t\t学生性别:%s\n",s->a[i].sex); printf("\t\t学生籍贯:%s\n",s->a[i].home); printf("\t\t学生电话:%s\n",s->a[i].tel); } } void insert(struct slist *s,int i) { int j; if(i<0||i>s->len || s->len == MAX) { printf("插入位置不合法或者顺序表已满\n"); } else { for(j=s->len-1;j>=i;j--) { s->a[j+1]=s->a[j]; } printf("\t\t请输入学生编号:"); scanf("%d",&s->a[i].id); printf("\t\t请输入学生姓名:"); scanf("%s",s->a[i].name); printf("\t\t请输入学生性别:"); scanf("%s",s->a[i].sex); printf("\t\t请输入学生籍贯:"); scanf("%s",s->a[i].home); printf("\t\t请输入学生电话:"); scanf("%s",s->a[i].tel); s->len++; printf("插入成功!\n"); } printf("插入后学生如下:\n"); output(s); } void del(struct slist *s,int i) { int j; if(i<0||i>s->len-1) { printf("位置不合法!\n"); } else { for(j=i;j<s->len-1;j++) { s->a[j]=s->a[j+1]; } s->len--; printf("删除成功\n"); } } void update(struct slist *s,int i) { if(i<0||i>s->len-1) { printf("位置不合法!\n"); } else { printf("\t\t请输入学生姓名:"); scanf("%s",s->a[i].name); printf("\t\t请输入学生性别:"); scanf("%s",s->a[i].sex); printf("\t\t请输入学生籍贯:"); scanf("%s",s->a[i].home); printf("\t\t请输入学生电话:"); scanf("%s",s->a[i].tel); printf("修改成功!\n"); } } void main() { int n,num,i,id; struct slist s; s.len=0; while(1) { printf("\t\t===============================\n"); printf("\t\t1、录入一个或多个学生信息\n"); printf("\t\t2、打印所有学生信息\n"); printf("\t\t3、插入一个学生信息\n"); printf("\t\t4、删除一个学生信息\n"); printf("\t\t5、修改一个学生信息\n"); printf("\t\t0、退出\n"); printf("\t\t===============================\n"); printf("请输入您的选择:"); scanf("%d",&n); switch(n) { case 1: printf("请输入要录入的学生数量:"); scanf("%d",&num); add(&s,num); break; case 2: output(&s); break; case 3: printf("请输入要插入下标:"); scanf("%d",&i); insert(&s,i); break; case 4: printf("请输入要删除的下标:"); scanf("%d",&i); del(&s,i); break; case 5: printf("请输入要修改的下标:"); scanf("%d",&i); update(&s,i); break; case 0:return;break; default:printf("编号输入有误!\n");break; } } }