单链表应用示例

单链表应用示例
单链表应用示例

学生成绩管理

以单链表作为存储结构,设计和实现某班某门课程成绩管理的完整程序。程序要求完成如下功能:

(1)创建成绩链表,学生数据包含学生的学号、姓名和成绩。

(2)可以在指定学号学生前插入学生成绩数据。

(3)可以删除指定学号的学生数据。

(4)可以计算学生的总数。

(5)可以按学号和姓名查找学生。

(6)可以显示所有学生的成绩。

(7)可以把学生成绩按从高到低的顺序排列。

此处的设计思想基本与顺序表相同,只是对保存学生成绩的线性表采用不同的存储结构实现。本例中用到的学生数据也是程序运行时由用户从键盘输入,保存到一个单链表中。学生结构体类型的定义与顺序表应用举例处的定义相同,用C语言描述如下:typedef struct Student /*学生类型定义*/

{ int score; /*成绩*/

char sno[5],sname[8]; /*学号,姓名*/

}Student;

当学生的学号为“#”时,也是表示数据输入的结束。单链表中保存的数据元素均为学生Student类型,则单链表定义如下:

typedef struct Node /*结点类型定义*/

{ Student studentInfo; /*学生信息*/

struct Node *next; /*指向后继元素的指针域*/

}LinkList;

对学生的成绩按从高到低排序时,使用的也是直接插入排序思想。此外,为了排序后还能在原单链表上继续进行操作,这里是把单链表中的内容复制到一个新单链表中,对新单链表排序,原单链表不变。

下面是以单链表作为存储结构实现的学生某门课程成绩管理的完整C语言程序。

#include

#include

#include

#include

typedef struct Student /*学生类型定义*/

{ int score; /*成绩*/

char sno[5],sname[8]; /*学号,姓名*/

}Student;

typedef struct Node /*结点类型定义*/

{ Student studentInfo; /*学生信息*/

struct Node *next; /*指向后继元素的指针域*/

}LinkList;

void display(LinkList *p) /*在屏幕上显示一个学生的成绩信息*/

{ printf("\n\n\nno\t\tname\t\tscore: ");

printf("\n%s",p->studentInfo.sno); /*打印学号*/

printf("\t\t ");

printf("%s",p->studentInfo.sname); /*打印姓名*/

printf("\t\t ");

printf("%-4d\n",p->studentInfo.score); /*打印成绩*/

}

void displayAll(LinkList *L) /*在屏幕上显示所有学生的成绩信息*/ { LinkList *p;

p=L->next;

printf("\n\n\nno\t\tname\t\tscore: ");

while(p)

{ printf("\n%s",p->studentInfo.sno); /*打印学号*/

printf("\t\t ");

printf("%s",p->studentInfo.sname); /*打印姓名*/

printf("\t\t ");

printf("%-4d\n",p->studentInfo.score);/*打印成绩*/

p=p->next;

}

}

LinkList *inputdata( ) /*输入学生信息*/

{ LinkList *s=NULL ; /*s是指向新建结点的指针*/ char sno[5]; /*存储学号的数组*/

printf("\n ");

printf(" no: ");

scanf("%s",sno); /*输入学号*/

if(sno[0]=='#') /*#结束输入*/

return s;

s=( LinkList *)malloc(sizeof(LinkList));

strcpy(s->studentInfo.sno,sno);

if(strlen(sno)>4) /*如果sno字符个数大于等于5,因为字符串没有'\0'结束标志,

在读数据时将把姓名字符一起读到sno数组,因此做了如下处理*/ s->studentInfo.sno[4]='\0';

printf(" name: ");

scanf("%s",s->studentInfo.sname); /*输入姓名*/

printf("score: ");

scanf("%d",&s->studentInfo.score);/*输入成绩*/

return s;

}

LinkList *createTailList( ) /*以尾插法建立带头结点的学生信息单链表*/

{ LinkList *L,*s, *r; /*L头指针,r尾指针,s是指向新建结点的指针*/ L=( LinkList *)malloc(sizeof (LinkList)); /*建立头结点,申请结点存储空间*/

r=L; /*尾指针指向头结点*/

printf("\请输入学生成绩,当学号no为\"#\"时结束:\n\n ");

while (1) /*逐个输入学生的成绩*/

{ s=inputdata( );

if(!s) break; /*s为空时结束输入*/

r->next=s; /*把新结点插入到尾指针后*/

r=s; /*r 指向新的尾结点*/ }

r->next=NULL; /*尾指针的指针域为空*/

displayAll(L); /*显示所有学生信息*/

return L;

}

Void locateElemByno(LinkList *L, char ch[5]) /*按学号查找学生的算法*/

{ LinkList *p=L->next; /*从第一个结点开始查找*/ while ( p && (strcmp(p->studentInfo.sno,ch)!=0))/*p不空且输入学号与链表中学号不等*/ p = p ->next;

if (!p)

{ printf("\n\n\tDon't find the student!\n" );

}

else

{ display(p); /*显示查找到的学生信息*/

}

}

void locateElemByname(LinkList *L, char sname[8])/*按姓名查找学生的算法*/

{ LinkList *p=L->next; /*从第一个结点开始查找*/ while ( p&& (strcmp(p->studentInfo.sname,sname)!=0)) /*p不空且输入姓名与

链表中姓名不等*/ p = p ->next;

if (!p)

{ printf("\n\n\tDon't find the student!\n" ); }

else

{display(p); /*显示查找到的学生信息*/

}

}

int lengthList (LinkList *L) /*求学生总人数的算法*/

{ LinkList * p=L->next; /* p指向第一个结点*/

int j=0;

while (p)

{ p=p->next; j++ ;} /* p所指的是第j 个结点*/

return j;

}

void insertElem ( LinkList *L, char ch[5]) /*在带头结点的单链表L中指定学号前插入学生*/ { LinkList *p,*s;

p=L; /*从头结点开始查找学号为ch的结点的前趋结点p */

while ((p->next) && (strcmp(p->next->studentInfo.sno,ch)!=0))

p = p ->next;

s=inputdata(); /*输入欲插入学生信息*/

s->next=p->next;

p->next=s;

}

void deleteElem (LinkList *L, char ch[5]) /*删除给定学号的学生信息的算法*/

{ LinkList *p,*q;

p=L;

while ( (p->next)&&(strcmp(p->next->studentInfo.sno,ch)!=0 ))

{ p=p->next; /*从头结点开始查找学号为ch的结点的前趋结点p*/

}

if (!p->next) /* 已经扫描到表尾也没找到*/

{ printf("\n\n\tDon't find the student!\n" );

}

else

{ q=p->next; /*q指向学号为ch的结点*/

printf("\n\ndeleted student's information:");

display(q);

p->next=q->next; /*改变指针*/

free(q); /*释放q占用空间*/

printf("\n\nall student's information :");

displayAll(L);

}

}

void insertSort(LinkList *L) /*用直接插入排序思想把学生的成绩按从高到低排序,

结果保存在新有序链表中,原链表不变*/

{ L inkList *L1,*p; /*L1有序链表的表头,p插入位置前结点*/ LinkList *q,*s; /*q欲插入L1中的结点*/

int len;

len=lengthList (L) ;

L1=( LinkList *)malloc(sizeof (LinkList)); /*建立头结点,申请结点存储空间*/

if (L->next) /*链表L非空*/

{ /*生成有序链表的第一个结点*/

s=( LinkList *)malloc(sizeof (LinkList)); /*建立结点,申请结点存储空间*/

strcpy(s->studentInfo .sno ,L->next->studentInfo.sno);

strcpy(s->studentInfo .sname,L->next->studentInfo.sname);

s->studentInfo .score =L->next->studentInfo.score;

s->next =NULL;

L1->next=s; /*只有原单链表的第一个结点的有序链表L1*/

q=L->next->next; /*原单链表的第二个结点,q即要插入有序链表L1中的结点*/ }

else

{ printf("\nthe student link list is empty!!!!\n");

return;

}

while(q) /*链表L中有结点*/

{ p=L1 ; /*从链表L1的第一个结点开始比较*/

while((p->next) && (p->next->studentInfo.score>=q->studentInfo.score))

p=p->next ; /*查找插入位置前结点*/

/*生成欲插入有序链表中的结点*/

s=( LinkList *)malloc(sizeof (LinkList));/*建立结点,申请结点存储空间*/

strcpy(s->studentInfo .sno ,q->studentInfo.sno);

strcpy(s->studentInfo .sname ,q->studentInfo.sname);

s->studentInfo .score =q->studentInfo.score;

if(!p->next) /*p是有序链表的最后一个结点*/

{ s->next =NULL ;

p->next =s;

}

else

{ s->next =p->next ;

p->next =s;

}

q=q->next; /*下一个欲插入有序链表的结点*/ }/*while(!q)*/

displayAll(L1); /*显示生成的有序链表*/

}

void main()

{ printf("=============================================\n\n");

printf(" 带头结点的学生成绩管理程序\n\n");

printf("=============================================\n\n");

LinkList *L;

char ch[5],sname[8];

int b=1;

while(b)

{ int a;

printf("\n\n");

printf(" <1>创建(带头尾插)<2>指定学号前插入<3>按学号删除\n ");

printf("<4>计算学生总数<5> 按学号查找<6> 按姓名查找\n");

printf(" <7>显示所有学生<8>成绩排序<9> 退出\n");

printf("\n请输入功能选项:");

scanf("%d",&a);

switch(a){

case 1:

L=CreateTailList();

break;

case 2:

printf("\n输入欲在哪个学号前插入数据:");

scanf("%s",ch);

insertElem(L, ch) ;

break;

case 3:

printf("\n输入欲删除学生的学号:");

scanf("%s",ch);

deleteElem(L, ch) ;

break;

case 4:

printf(" \n学生总数为:%d \n",lengthList (L) );

break;

case 5:

printf("\n输入欲查找学生的学号:");

scanf("%s",ch);

locateElemByno(L, ch) ;break;

case 6:

printf("\n输入欲查找学生的姓名:");

scanf("%s",sname);

locateElemByname(L, sname );break;

case 7:

displayAll(L);

break;

case 8:

insertSort(L);

break;

case 9:

printf("\n已退出\n");

b=0;break;

};

}

}

上机运行程序后,程序执行结果如图2.31(a)~(i)所示。

(b ) 建立成绩链表时输入数据 替换

(c ) 建好的成绩链表数据

(d ) 在学号0002的学生前插入数据

(e ) 在学号0002的学生前插入数据后显示所有学生数据

(a ) 程序运行的初始界面

(f ) 删除学号0009的学生数据后显示的数据

(g ) 查找学号为0002的学生数据

(h ) 查找姓名为john 的学生数据

(i ) 学生成绩排序的结果 图2.31 单链表应用程序上机运行结果

excel表格的基本操作快捷指令

excel表格的基本操作 Excel 快捷键和功能键 Ctrl 组合快捷键 按键说明 Ctrl+( 取消隐藏选定范围内所有隐藏的行。 Ctrl+) 取消隐藏选定范围内所有隐藏的列。 Ctrl+& 将外框应用于选定单元格。 Ctrl+_ 从选定单元格删除外框。 Ctrl+~ 应用“常规”数字格式。 Ctrl+$ 应用带有两位小数的“货币”格式(负数放在括号中)。 Ctrl+% 应用不带小数位的“百分比”格式。 Ctrl+^ 应用带有两位小数的“指数”格式。 Ctrl+# 应用带有日、月和年的“日期”格式。 Ctrl+@ 应用带有小时和分钟以及AM 或PM 的“时间”格式。 Ctrl+! 应用带有两位小数、千位分隔符和减号(-)(用于负值)的“数值”格式。Ctrl+- 显示用于删除选定单元格的“删除”对话框。 Ctrl+* 选择环绕活动单元格的当前区域(由空白行和空白列围起的数据区域)。在数据透视表中,它将选择整个数据透视表。 Ctrl+: 输入当前时间。 Ctrl+; 输入当前日期。 Ctrl+` 在工作表中切换显示单元格值和公式。 Ctrl+' 将公式从活动单元格上方的单元格复制到单元格或编辑栏中。 Ctrl+" 将值从活动单元格上方的单元格复制到单元格或编辑栏中。 Ctrl++ 显示用于插入空白单元格的“插入”对话框。 Ctrl+1 显示“单元格格式”对话框。 Ctrl+2 应用或取消加粗格式设置。 Ctrl+3 应用或取消倾斜格式设置。 Ctrl+4 应用或取消下划线。 Ctrl+5 应用或取消删除线。 Ctrl+6 在隐藏对象、显示对象和显示对象占位符之间切换。 Ctrl+7 显示或隐藏“常用”工具栏。 Ctrl+8 显示或隐藏大纲符号。 Ctrl+9 隐藏选定的行。 Ctrl+0 隐藏选定的列。 Ctrl+A 选择整个工作表。 如果工作表包含数据,则按Ctrl+A 将选择当前区域。再次按Ctrl+A 将选择整个工作表。 当插入点位于公式中某个函数名称的右边时,则会显示“函数参数”对话框。

《数据结构》实验报告 设计循环单链表

《数据结构》实验报告 1、实验名称:设计循环单链表 2、实验日期: 2013-3-26 3、基本要求: 1)循环单链表的操作,包括初始化、求数据元素个数、插入、删除、取数据元素; 2)设计一个测试主函数实际运行验证所设计循环单链表的正确性。 4、测试数据: 依次输入1,2,3,4,5,6,7,8,9,10,删除5,再依次输出数据元素。 5、算法思想或算法步骤: 主函数主要是在带头结点的循环单链表中删除第i个结点,其主要思想是在循环单链表中寻找到第i-1个结点并由指针p指示,然后让指针s指向a[i]结点,并把数据元素a[i]的值赋给x,最后把a[i]结点脱链,并动态释放a[i]结点的存储空间。 6、模块划分: 1)头文件LinList.h。头文件LinList.h中包括:结点结构体定义、初始化操作、求当前数据个数、插入一个结点操作、删除一个结点操作以及取一个数据元素操作; 2)实现文件dlb.cpp。包含主函数void main(void),其功能是测试所设计的循环单链表的正确性。

7、数据结构: 链表中的结点的结构体定义如下: typedef struct Node { DataType data; struct Node *next; }SLNode; 8、源程序: 源程序存放在两个文件中,即头文件LinList.h和实现文件dlb.cpp。//头文件LinList.h typedef struct Node { DataType data; struct Node *next; }SLNode; void ListInitiate(SLNode **head) //初始化 { *head=(SLNode *)malloc(sizeof(SLNode)); //申请头结点,由head指示其地址 (*head)->next=*head; }

数据结构课程设计单链表操作汇总

《数据结构课程设计》报告 题目:单链表操作 专业:计算机科学与技术 班级: 单链表操作 针对带头结点的单循环链表,编写实现以下操作的算法函数。

实现要求: ⑴单链表建立函数create:先输入数据到一维数组A[M]中,然后根据一维 数组A[M]建立一个单循环链表,使链表中个元素的次序与A[M]中各元素的次序相同,要求该函数的时间复杂度为O(m); ⑵定位查找函数Locate:在所建立的单循环链表中查找并返回值为key的 第1个元素的结点指针;若找不到,则返回NULL; ⑶求出该链表中值最大和次大的元素值,要求该算法的时间复杂度为O(m), 最大和次大的元素值通过指针变量带回,函数不需要返回值; ⑷将链表中所有值比key(值key通过形参传入)小的结点作为值为key的结 点前驱,所有值比key大的结点作为值为key的结点后继,并尽量保持原有结点之间的顺序,要求该算法的时间复杂度为O(m); ⑸设计一个菜单,具有上述处理要求和退出系统功能。 ⒈本人完成的工作: 一、定义结构体:LNode 二、编写以下函数: (1)建立单循环链表 (2)建立定位查找函数 (3)求出链表中最大和次大值 (4)将链表中的值和输入的Key比较,小的作为key前驱结点,大的作为key 的后继结点 三、设计具有上述处理要求和退出系统菜单 ⒉所采用的数据结构:单链表 数据结构的定义: typedef struct Node //定义结点的结构体 { DataType data; //数据域 struct Node *next; //指针域

}LNode; //结点的类型 ⒊所设计的函数 (1)Create(void) LNode *Create(void) //建立单循环链表,链表头结点head作为返回值{ int i,j,n,A[M]; //建立数组A【M】 LNode *head,*p,*move; head=(LNode*)malloc(sizeof(LNode)); //创建空单循环链表head->next=head; move=head; printf("请输入数组元素的个数:"); //输入数组 scanf("%d",&n); printf("请输入数组:"); for(i=0;idata=A[j]; p->next=move->next; move->next=p; move=move->next; } return head; //返回头指针

链表实验报告

C语言程序设计实验报告 实验一:链表的基本操作一·实验目的 1.掌握链表的建立方法 2.掌握链表中节点的查找与删除 3.掌握输出链表节点的方法 4.掌握链表节点排序的一种方法 5.掌握C语言创建菜单的方法 6.掌握结构化程序设计的方法 二·实验环境 1.硬件环境:当前所有电脑硬件环境均支持 2.软件环境:Visual C++6.0 三.函数功能 1. CreateList // 声明创建链表函数 2.TraverseList // 声明遍历链表函数 3. InsertList // 声明链表插入函数 4.DeleteTheList // 声明删除整个链表函数 5. FindList // 声明链表查询函数 四.程序流程图 五.程序代码 #include #include typedef int Elemtype; typedef int Status; typedef struct node//定义存储节点 { int data;//数据域 struct node *next;//结构体指针 } *linklist,node;//结构体变量,结构体名称 linklist creat (int n)//创建单链表 { linklist head,r,p;//定义头指针r,p,指针 int x,i; head=(node *)malloc(sizeof(node));//生成头结点

r=head;//r指向头结点 printf("输入数字:\n"); for(i=n;i>0;i--)//for 循环用于生成第一个节点并读入数据{ scanf("%d",&x); p=(node *)malloc(sizeof(node)); p->data=x;//读入第一个节点的数据 r->next=p;//把第一个节点连在头结点的后面 r=p;//循环以便于生成第二个节点 } r->next=0;//生成链表后的断开符 return head;//返回头指针 } void output (linklist head)//输出链表 { linklist p; p=head->next; do { printf("%3d",p->data); p=p->next; } while(p); printf("\n") } Status insert ( linklist &l,int i, Elemtype e)//插入操作 { int j=0; linklist p=l,s; while(jnext; ++j; } if(!p || j>i-1) return -1; else { s=(node *)malloc(sizeof(node)); s->data=e; s->next=p->next; p->next=s; return 1; } } Status delect ( linklist &l,int i, Elemtype &e)//删除操作 { int j=0; linklist p=l,q; while(jnext) { p=p->next; ++j; } if(!p->next || j>i-1) return -1;

数据透视表应用练习

数据透视表应用练习 "练习 1:创建报表视图 1. 在工作表中,选择包含数据的任意单元格。例如,单击单元格 A4。在“数据”菜单上,单击“数据透视表和数据透视图”。将显示向导。 2. 在向导的步骤 1 中,确保选择“Microsoft Excel 数据列表或数据库”作为第一个问题的答案。 3. 确保选择“数据透视表”作为下一个问题的答案。 4. 单击“完成”。 " :设置报表布局 "练习 2 现在将设置报表布局,以算出每位销售人员的销量。将字段放置到布局中时,报表布局的外观将发生更改。 1. 从“数据透视表字段列表”中,将“销售人员”字段拖动到标签为“将行字段拖至此处”的拖放区域。可以通过选择字段名称或字段名称前面的按钮拖动字段。如果将字段拖放到了错误的拖放区域,只需把它拖放到正确的拖放区域即可。 2. 从“数据透视表字段列表”中,将“订单金额”字段拖动到标签为“请将数据项拖至此处”的拖放区域。将字段拖放到数据项的拖放区域中时,彩色外框将消失,并将显示报表,其中显示有每位销售人员的销售总额。 " "练习 3:转动报表 在这个练习中,您将把数据从行方向转到列方向。 1. 单击“销售人员” 字段标题(在单元格 A4 中)。 2. 拖放“销售人员”字段标题到单元格 B3,B3 是在“总额”正上方的单元格。拖动时,只要获得灰色框光标并把光标指向目标单元格即可。 报表的外观发生更改,将按列方向显示销售人员姓名,而不是按行方向。

下一步,将“销售人员”字段移回到行方向。 操作步骤单击“销售人员”字段标题,将其拖放到单元格 A4。 " "练习 4:创建页视图 现在可以进行新的尝试:创建页视图。在本示例中,将显示销售人员的订单金额,不同国家/地区的数量显示在不同页面上。将字段拖放到标签为“将页字段拖至此处”的拖放区域。 ? 将“国家/地区”字段从“数据透视表字段列表”拖放到“将页字段拖至此处”区域。 " "练习 5:从报表中拖出字段 我们已经讲过,可以很容易地更改报表中包含的信息。现在可以看到如何删除字段。开始之前,注意现在在报表视图中显示的字段在“数据透视表字段列表”中用粗体字母显示。这将帮助您追踪已拖放到报表中的字段。 1. 单击工作表(单元格 A1)上的“国家/地区”字段标题,然后拖放到外边框外面的任何位置。例如,将它拖放到单元格 D2 中。 注意将字段拖动到布局区域外面后,一个红“X”显示在插入点下方。这个 X 表示该字段已从报表布局中删除。 2. 单击工作表(单元格 A3)上的“订单金额总额” 字段标题,然后拖放到外边框外面的任何位置。拖放字段时,外边框将扩张。 3. 单击工作表(单元格 A4)上的“销售人员”字段标题,然后拖放到外边框外面的任何位置。外边框看上去和开始操作之前一样。字段列表上的任何名称都不用粗体字母表示,因为该列表中没有字段用于数据透视表布局区域。 " "练习 6:使用向导创建透视表布局区域

单链表实验报告

计算机与信息技术学院综合性、设计性实验报告 一、实验目的 (1)熟悉顺序表的创建、取值、查找、插入、删除等算法,模块化程序设计方法。 二、实验仪器或设备 (1)硬件设备:CPU为Pentium 4 以上的计算机,内存2G以上 (2)配置软件:Microsoft Windows 7 与VC++6.0 三、总体设计(设计原理、设计方案及流程等) 设计原理: 单链表属于线性表,线性表的存储结构的特点是:用一组任意存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。因此,对于某个元素来说,不仅需要存储其本身的信息,还需要存储一个指示其直接后继的信息。 设计方案: 采用模块化设计的方法,设计各个程序段,最终通过主函数实现各个程序段的功能。设计时,需要考虑用户输入非法数值,所以要在程序中写入说可以处理非法数值的代码。 设计流程: 1. 引入所需的头文件; 2. 定义状态值; 3. 写入顺序表的各种操作的代码; 写入主函数,分别调用各个函数。在调用函数时,采用if结构进行判断输 入值是否非法,从而执行相应的程序 四、实验步骤(包括主要步骤、代码分析等) #include // EOF(=A Z 或F6),NULL #in clude // srand( ) ,rand( ),exit (n) #in clude // malloc( ),alloc( ),realloc() 等 #in clude // INT_MAX 等 #in clude #in clude #in clude // floor(),ceil( ),abs() #in clude // cout,ci n #in clude // clock( ),CLK_TCK,clock_t #defi ne TRUE 1 #defi ne FALSE 0 #defi ne OK 1 #defi ne ERROR 0 #defi ne INFEASIBLE -1

单链表的插入和删除实验报告

. 实验一、单链表的插入和删除 一、目的 了解和掌握线性表的逻辑结构和链式存储结构,掌握单链表的基本算法及相关的时间性能分析。 二、要求: 建立一个数据域定义为字符串的单链表,在链表中不允许有重复的字符串;根据输入的字符串,先找到相应的结点,后删除之。 三、程序源代码 #include"stdio.h" #include"string.h" #include"stdlib.h" #include"ctype.h" typedef struct node //定义结点 { char data[10]; //结点的数据域为字符串 struct node *next; //结点的指针域 }ListNode; typedef ListNode * LinkList; // 自定义LinkList单链表类型 LinkList CreatListR1(); //函数,用尾插入法建立带头结点的单链表

ListNode *LocateNode(); //函数,按值查找结点 void DeleteList(); //函数,删除指定值的结点void printlist(); //函数,打印链表中的所有值 void DeleteAll(); //函数,删除所有结点,释放内存 //==========主函数============== void main() { char ch[10],num[10]; LinkList head; head=CreatListR1(); //用尾插入法建立单链表,返回头指针printlist(head); //遍历链表输出其值 printf(" Delete node (y/n):");//输入“y”或“n”去选择是否删除结点scanf("%s",num); if(strcmp(num,"y")==0 || strcmp(num,"Y")==0){ printf("Please input Delete_data:"); scanf("%s",ch); //输入要删除的字符串 DeleteList(head,ch); printlist(head); } DeleteAll(head); //删除所有结点,释放内存 } //==========用尾插入法建立带头结点的单链表

数据透视表应用练习.

数据透视表应用练习 "练习1:创建报表视图 1. 在工作表中,选择包含数据的任意单元格。例如,单击单元格A4。在“数据”菜单上,单击“数据透视表和数据透视图”。将显示向导。 2. 在向导的步骤1 中,确保选择“Microsoft Excel 数据列表或数据库”作为第一个问题的答案。 3. 确保选择“数据透视表”作为下一个问题的答案。 4. 单击“完成”。 " "练习2:设置报表布局 现在将设置报表布局,以算出每位销售人员的销量。将字段放置到布局中时,报表布局的外观将发生更改。1. 从“数据透视表字段列表”中,将“销售人员”字段拖动到标签为“将行字段拖至此处”的拖放区域。 可以通过选择字段名称或字段名称前面的按钮拖动字段。如果将字段拖放到了错误的拖放区域,只需把它拖放到正确的拖放区域即可。 2. 从“数据透视表字段列表”中,将“订单金额”字段拖动到标签为“请将数据项拖至此处”的拖放区域。 将字段拖放到数据项的拖放区域中时,彩色外框将消失,并将显示报表,其中显示有每位销售人员的销售总额。" "练习3:转动报表 在这个练习中,您将把数据从行方向转到列方向。 1. 单击“销售人员”字段标题(在单元格A4 中)。 2. 拖放“销售人员”字段标题到单元格B3,B3 是在“总额”正上方的单元格。拖动时,只要获得灰色框光标并把光标指向目标单元格即可。 报表的外观发生更改,将按列方向显示销售人员姓名,而不是按行方向。 下一步,将“销售人员”字段移回到行方向。 操作步骤单击“销售人员”字段标题,将其拖放到单元格A4。 " "练习4:创建页视图 现在可以进行新的尝试:创建页视图。在本示例中,将显示销售人员的订单金额,不同国家/地区的数量显示在不同页面上。将字段拖放到标签为“将页字段拖至此处”的拖放区域。 ?将“国家/地区”字段从“数据透视表字段列表”拖放到“将页字段拖至此处”区域。 " "练习5:从报表中拖出字段 我们已经讲过,可以很容易地更改报表中包含的信息。现在可以看到如何删除字段。开始之前,注意现在在报表视图中显示的字段在“数据透视表字段列表”中用粗体字母显示。这将帮助您追踪已拖放到报表中的字段。 1. 单击工作表(单元格A1)上的“国家/地区”字段标题,然后拖放到外边框外面的任何位置。例如,将它拖放到单元格D2 中。 注意将字段拖动到布局区域外面后,一个红“X”显示在插入点下方。这个X 表示该字段已从报表布局中删除。 2. 单击工作表(单元格A3)上的“订单金额总额”字段标题,然后拖放到外边框外面的任何位置。 拖放字段时,外边框将扩张。 3. 单击工作表(单元格A4)上的“销售人员”字段标题,然后拖放到外边框外面的任何位置。 外边框看上去和开始操作之前一样。字段列表上的任何名称都不用粗体字母表示,因为该列表中没有字段用于数据透视表布局区域。 " "练习6:使用向导创建透视表布局区域 开始前,请先查看源数据。“订单金额”字段包含销售数据,“销售人员”字段包含销售人员姓名。在本练习单元中您将使用这两个字段,以及“国家/地区”字段,它标识每位销售人员所在的国家。 操作步骤选择工作表中包含数据的任一单元格。例如,单击单元格A4。在“数据”菜单上,单击“数据

Excel表格的基本操作教程

ExcelExcel表格的基本操作教程系列 也许你已经在Excel中完成过上百张财务报表,也许你已利用Excel函数实现过上千次的复杂运算,也许你认为Excel也不过如此,甚至了无新意。但我们平日里无数次重复的得心应手的使用方法只不过是Excel全部技巧的百分之一。本专题从Excel中的一些鲜为人知的技巧入手,领略一下关于Excel的别样风情。 一、让不同类型数据用不同颜色显示 在工资表中,如果想让大于等于2000元的工资总额以“红色”显示,大于等于1500元的工资总额以“蓝色”显示,低于1000元的工资总额以“棕色”显示,其它以“黑色”显示,我们可以这样设置。 1.打开“工资表”工作簿,选中“工资总额”所在列,执行“格式→条件格式”命令,打开“条件格式”对话框。单击第二个方框右侧的下拉按钮,选中“大于或等于”选项,在后面的方框中输入数值“2000”。单击“格式”按钮,打开“单元格格式”对话框,将“字体”的“颜色”设置为“红

色”。 2.按“添加”按钮,并仿照上面的操作设置好其它条件(大于等于1500,字体设置为“蓝色”;小于1000,字体设置为“棕色”)。 3.设置完成后,按下“确定”按钮。 看看工资表吧,工资总额的数据是不是按你的要求以不同颜色显示出来了。 六、让数据按需排序 如果你要将员工按其所在的部门进行排序,这些部门名称既的有关信息不是按拼音顺序,也不是按笔画顺序,怎么办?可采用自定义序列来排序。 1.执行“格式→选项”命令,打开“选项”对话框,进入“自定义序列”标签中,在“输入序列”下面的方框中输入部门排序的序列(如“机关,车队,一车间,二车间,三车间”等),单击“添加”和“确定”按钮退出。 2.选中“部门”列中任意一个单元格,执行“数据→排序”命令,打开“排序”对话框,单击“选项”按钮,弹出“排序选项”对话框,按其中的下拉按钮,选中刚才自定义

C语言链表实验报告

链表实验报告 一、实验名称 链表操作的实现--学生信息库的构建 二、实验目的 (1)理解单链表的存储结构及基本操作的定义 (2)掌握单链表存储基本操作 (3)学会设计实验数据验证程序 【实验仪器及环境】计算机 Window XP操作系统 三、实验内容 1、建立一个学生成绩信息(学号,姓名,成绩)的单链表,按学号排序 2、对链表进行插入、删除、遍历、修改操作。 3、对链表进行读取(读文件)、存储(写文件) 四、实验要求 (1)给出终结报告(包括设计过程,程序)-打印版 (2)对程序进行答辩

五、实验过程、详细内容 1、概念及过程中需要调用的函数 (1)链表的概念结点定义 结构的递归定义 struct stud_node{ int num; char name[20]; int score; struct stud_node *next; }; (2)链表的建立 1、手动输入 struct stud_node*Create_Stu_Doc() { struct stud_node *head,*p; int num,score; char name[20]; int size=sizeof(struct stud_node); 【链表建立流程图】

2、从文件中直接获取 先建立一个 (3)链表的遍历 (4 )插入结点 (5)删除结点 (6)动态储存分配函数malloc () void *malloc(unsigned size) ①在内存的动态存储区中分配一连续空间,其长度为size ②若申请成功,则返回一个指向所分配内存空间的起始地址的指针 ③若申请不成功,则返回NULL (值为0) ④返回值类型:(void *) ·通用指针的一个重要用途 ·将malloc 的返回值转换到特定指针类型,赋给一个指针 【链表建立流程图】 ptr ptr ptr->num ptr->score ptr=ptr->next head pt r s s->next = ptr->next ptr->next = s 先连后断 ptr2=ptr1->next ptr1->next=ptr2->next free (ptr2)

链表基本操作实验报告

实验2 链表基本操作实验 一、实验目的 1.定义单链表的结点类型。 2.熟悉对单链表的一些基本操作和具体的函数定义。 3.通过单链表的定义掌握线性表的链式存储结构的特点。 二、实验内容与要求 该程序的功能是实现单链表的定义和主要操作。如:单链表建立、输出、插入、删除、查找等操作。该程序包括单链表结构类型以及对单链表操作的具体的函数定义和主函数。程序中的单链表(带头结点)结点为结构类型,结点值为整型。 要求: 同学们可参考指导书实验2程序、教材算法及其他资料编程实现单链表相关操作。必须包括单链表创建、输出、插入、删除操作,其他操作根据个人情况增减。 三、算法分析与设计。 1.创建单链表: 头结点L

...... 2.单链表插入

s s->data=x; s->next=p->next; p->next=s; 3.单链表的删除: p->next=p->next->next;

四、运行结果 1.单链表初始化 2.创建单链表 3.求链表长度 4.检查链表是否为空 5.遍历链表 6.从链表中查找元素 7.从链表中查找与给定元素值相同的元素在顺序表中的位置

8.向链表中插入元素 插入元素之后的链表 9.从链表中删除元素 删除位置为6的元素(是3) 10.清空单链表 五、实验体会 经过这次单链表基本操作实验,自己的编程能力有了进一步的提高,认识到自己以前在思考一个问题上思路不够开阔,不能灵活的表达出自己的想法,虽然在打完源代码之后出现了一些错误,但是经过认真查找、修改,最终将错误一一修正,主要是在写算法分析的时候出现了障碍,经过从网上查找资料,自己也对程

单链表的基本操作实验报告

湖南第一师范学院信息科学与工程系实验报告 课程名称:数据结构与算法成绩评定: 实验项目名称:单链表的基本操作指导教师: 学生姓名:沈丽桃学号: 10403080118 专业班级: 10教育技术 实验项目类型:验证实验地点:科B305 实验时间: 2011 年 10 月20 日一、实验目的与要求: 实验目的:实现线性链表的创建、查找、插入、删除与输出。 基本原理:单链表的基本操作 二、实验环境:(硬件环境、软件环境) 1.硬件环境:奔ⅣPC。 2.软件环境:Windows XP 操作系统,TC2.0或VC++。 三、实验内容:(原理、操作步骤、程序代码等) #include #include #include struct celltype { int element; struct celltype*next; }; typedef int position; void main() { struct celltype*head,*p; int x,choice; void INSERT(int x,struct celltype*p); void LOCATE(int x,struct celltype*p); void DELETE(int x,struct celltype*p); p=(struct celltype*)malloc(sizeof(struct celltype)); head=p; p->element=0; p->next=NULL; printf(“Please option:1:Insert 2:Locate 3:Delete\n”); printf(“Please choose:”); scanf(“%d”,&choice); switch(choice) case 1: printf(“Please input a node:”); scanf(“%d”,&x);

表的基本操作

教学内容: 4.3 表的基本操作 4.3.1 表的打开和关闭 1、使用菜单打开表 (1)选择“文件”菜单中的“打开”项,在弹出的“打开”对话框中“文件类型”列表框中选择“表(*.dbf)。 (2)选择或输入要打开的表文件名,单击“确定”打开表。 2、用命令打开表 命令格式:USE 表名 [EXCLUSIVE|SHARED] 3、数据表的关闭 如果打开的表是数据库表,则在关闭数据库的同时,该数据库中的所有表也将同时关闭。 如果打开的是自由表,则可用以下命令关闭该表。 命令格式1:USE 命令功能:关闭当前数据表。 命令格式2:CLOSE TABLE 命令功能:关闭所有打开的数据表。 4.3.2 数据的输入 1、使用浏览器输入数据 (1) 打开要输入数据的表。 (2) 选择“显示”菜单中“浏览”或“编辑“项;选择“浏览”,则显示”浏览“窗口;选择“编辑”,则显示“编辑”窗口。 (3)选择“显示”菜单中的“追加方式”,可向表中输入新记录的数据。 2、使用APPEND命令在当前数据表的尾部添加新记录 命令格式:APPEND [BLANK] 3、使用INSERT命令在当前表的任意位置插入一条新记录 命令格式:INSERT [BLANK][BEFORE] 4、备注型和通用型字段数据的输入 (1)备注型字段数据的输入,操作步骤如下: ①打开表的“编辑”或“浏览”窗口。

②把光标移到备注型字段下双击左键或按Ctrl+PageDown或Ctrl+PageUp键,进入备注字段的编辑窗口。 ③在备注字段的编辑窗口,可以输入或修改备注型数据。 (2)通用型数据的输入 通用型字段数据多数是用于存储OLE对象,如,图像、声音、电子表格和文字处理文档等,其长度也是不确定的。给通用型字段输入数据,操作步骤如下: ①打开表的“编辑”或“浏览”窗口。 ②把光标移到通用型字段下双击左键或按Ctrl+PageDown或Ctrl+PageUp键,进入通用字段的编辑窗口。 ③选择“编辑”菜单中“插入对象”,在“插入对象”窗口,选择“由文件创建”按钮,单击“浏览”按钮,选择要插入的文件。 ④单击“确定”按钮,选择的对象被插入到通用字段中。 4.3.3 记录的浏览 1、浏览数据窗口的定制 (1)打开表的“浏览”窗口。 (2)用鼠标拖动某一字段到指定处,可改变字段的显示顺序。 (3)可以使用鼠标调整字段的显示宽度。 (4)在表“浏览”窗口的左下角有一个窗口拆分条,把它拖到一个适当的位置,就可以把“浏览”窗口拆分成两个窗口,将其改变成有“浏览”和“编辑”两种显示方式的窗口。(5)选择“显示”菜单中的“网格线”,可以显示或隐藏浏览窗口中的网格。 2、记录的筛选 (1)打开表的“浏览”窗口。 (2)在“表”菜单中,选择“属性”命令,弹出“工作区属性”对话框。 (3)在“工作区属性”对话框中,可以直接在“数据过滤器”文本框中输入筛选表达式,或者选择“数据过滤器”框后面的“浏览”(…)按钮,在“表达式生成器”对话框中创建一个表达式。 (4)单击“确定”按钮,则在“浏览”窗口中只显示筛选过的记录。 3、字段的筛选 (1)打开表的“浏览”窗口,选择“表”菜单中的“属性”。 (2)在“工作区”属性对话框的“允许访问”框内,选中“字段筛选指定的字段”,单击“字段筛选”按钮,弹出“字段选择器”对话框。 (3)在“字段选择器”对话框中,选择“所有字段”框内需要显示的字段,单击“添加”按钮,将所需字段移入“选字字段”栏中。 (4)在选定了所需字段后,单击“确定”按钮。返回“工作区属性”对话框,单击“确定”按钮,关闭“工作区属性”对知框。 4、使用命令浏览表 命令格式1:BROWSE [范围] [FIELDS 字段表][FOR 条件]

链表基本操作实验报告记录

链表基本操作实验报告记录

————————————————————————————————作者:————————————————————————————————日期:

实验2链表基本操作实验 一、实验目的 1.定义单链表的结点类型。 2.熟悉对单链表的一些基本操作和具体的函数定义。 3.通过单链表的定义掌握线性表的链式存储结构的特点。 二、实验内容与要求 该程序的功能是实现单链表的定义和主要操作。如:单链表建立、输出、插入、删除、查找等操作。该程序包括单链表结构类型以及对单链表操作的具体的函数定义和主函数。程序中的单链表(带头结点)结点为结构类型,结点值为整型。 要求: 同学们可参考指导书实验2程序、教材算法及其他资料编程实现单链表相关操作。必须包括单链表创建、输出、插入、删除操作,其他操作根据个人情况增减。 三、算法分析与设计。 1.创建单链表: LinkedList LinkedListCreat( ) 创建链表函数 LinkedList L=LinkedListInit(),p, r; 调用初始化链表函数 r=L; r指向头结点 使用malloc函数动态分配存储空间,指针p指向新开辟的结点,并将元素存 放到新开辟结点的数据域, p=(LinkedList)malloc(sizeof(LNode)); p->data=x; r->next=p; 将新的结点链接到头结点r之后 r=p; r指向p结点 scanf("%d",&x); 满足条件循环输入链表元素 while(x!=flag) 当输入不为-1时循环 r->next=NULL; return L; 将链表结尾赋空值,返回头结点L 头结点L L ...... ^ ^ An A1 A2

数据结构-单链表实验报告

单链表实验报告 一、实验目的 1、帮助读者复习C++语言程序设计中的知识。 2、熟悉线性表的逻辑结构。 3、熟悉线性表的基本运算在两种存储结构上的实现,其中以熟悉链表的操作为侧重点。 二、实验内容 [问题描述] 实现带头结点的单链表的建立、求长度,取元素、修改元素、插入、删除等单链表的基本操作。 [基本要求] (1)依次从键盘读入数据,建立带头结点的单链表; (2)输出单链表中的数据元素 (3)求单链表的长度; (4)根据指定条件能够取元素和修改元素; (5)实现在指定位置插入和删除元素的功能。 三、算法设计 (1)建立带表头结点的单链表;首先输入结束标志,然后建立循环逐个输入数据,直到输入结束标志。 (2)输出单链表中所有结点的数据域值;首先获得表头结点地址,然后建立循环逐个输出数据,直到地址为空。 (3)输入x,y在第一个数据域值为x的结点之后插入结点y,若无结点x,则在表尾插入结点y;建立两个结构体指针,一个指向当前结点,另一个指向当前结点的上一结点,建立循环扫描链表。当当前结点指针域不为空且数据域等于x的时候,申请结点并给此结点数据域赋值为y,然后插入当前结点后面,退出函数;当当前结点指针域为空的时候,申请结点并给此结点数据域赋值为y,插入当前结点后面,退出函数。 (4)输入k,删除单链表中所有的结点k,并输出被删除结点的个数。建立三个结构体指针,一个指向当前结点,另一个指向当前结点的上一结点,最后一个备用;建立整形变量l=0;建立循环扫描链表。当当前结点指针域为空的时候,如果当前结点数据域等于k,删除此结点,l++,跳出循环,结束操作;如果当前结点数据域不等于k,跳出循环,结束操作。当当前结点指针域不为空的时候,如果当前结点数据域等于k,删除此结点,l++,继续循环操作;如果当前结点数据域不等于k,指针向后继续扫描。循环结束后函数返回变量l的值,l便是删除的结点的个数。

单链表实验报告

单链表实验报告

————————————————————————————————作者:————————————————————————————————日期:

计算机与信息技术学院综合性、设计性实验报告 专业:网络工程年级/班级:大二 2016—2017学年第一学期 课程名称数据结构指导教师李四 学号姓名16083240XX 张三 项目名称单链表的基本操作实验类型综合性/设计性实验时间2017.10.3 实验地点216机房 一、实验目的 (1)熟悉顺序表的创建、取值、查找、插入、删除等算法,模块化程序设计方法。 二、实验仪器或设备 (1)硬件设备:CPU为Pentium 4以上的计算机,内存2G以上 (2)配置软件:Microsoft Windows 7与VC++6.0 三、总体设计(设计原理、设计方案及流程等) 设计原理: 单链表属于线性表,线性表的存储结构的特点是:用一组任意存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。因此,对于某个元素来说,不仅需要存储其本身的信息,还需要存储一个指示其直接后继的信息。 设计方案: 采用模块化设计的方法,设计各个程序段,最终通过主函数实现各个程序段的功能。设计时,需要考虑用户输入非法数值,所以要在程序中写入说可以处理非法数值的代码。 设计流程: 1.引入所需的头文件; 2.定义状态值; 3.写入顺序表的各种操作的代码; 写入主函数,分别调用各个函数。在调用函数时,采用if结构进行判断输入值是否非法,从而执行相应的程序 四、实验步骤(包括主要步骤、代码分析等) #include<stdio.h>// EOF(=^Z或F6),NULL #include<stdlib.h> // srand(),rand(),exit(n) #include<malloc.h> // malloc( ),alloc( ),realloc()等 #include //INT_MAX等 #include #include // floor(),ceil( ),abs( ) #include<iostream.h> // cout,cin #include // clock(),CLK_TCK,clock_t #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0

单链表的定义及其基本操作技巧

单链表的定义及基本操作 一、实验目的、意义 (1)理解线性表中带头结点单链表的定义和逻辑图表示方法。 (2)熟练掌握单链表的插入,删除和查询算法的设计与实现。 (3)根据具体问题的需要,设计出合理的表示数据的链表结构,并设计相关算法。 二、实验内容及要求 说明1:本次实验中的链表结构均为带头结点的单链表。 说明2: 学生在上机实验时,需要自己设计出所涉及到的函数,同时设计多组输入数据并编写主程序分别调用这些函数,调试程序并对相应的输出作出分析;修改输入数据,预期输出并验证输出的结果,加深对有关算法的理解。 具体要求: 建立单链表,完成链表(带表头结点)的基本操作:建立链表、插入、删除、查找、输出;其它基本操作还有销毁链表、将链表置为空表、求链表的长度、获取某位置结点的内容、搜索结点。 三、实验所涉及的知识点 数据结构、C语言语法函数、结构体类型指针、单链表(建表、初始化链表、求表长、插入、删除、查询算法)等。 四、实验结果及分析 (所输入的数据及相应的运行结果,运行结果要有提示信息,运行结果采用截图方式给出。)

五、总结与体会 (调试程序的心得与体会,若实验课上未完成调试,要认真找出错误并分析原因等。) 调试程序时,出现了许多错误。如:结构体类型指针出错,忽略了释放存储空间,对头插法建表、尾插法建表不熟悉等。另外还有一些语法上的错误。由于对所学知识点概念模糊,试验课上未能完成此次上机作业。后来经过查阅教材,浏览网页等方式,才完成试验。这次试验出现错误最重要的原因就是对课本知识点理解不深刻以及编写代码时的粗心。以后要都去练习、实践,以完善自己的不足。 六、程序清单(包含注释) //单链表

实验三 表的基本操作

实验三表的基本操作 一、实验目的 1.掌握表建立的方法以及修改表结构的方法。 2.掌握表中数据输入的方法。 3.掌握记录指针的移动方法。 4.掌握表的基本操作:追加、插入、修改、显示、删除和恢复记录。 5.掌握表中的数据访问控制方式。 6.掌握表的排序和索引及使用。 7.掌握多个工作区和多表的操作方法。 二、实验内容和步骤 1.创建自由表。 (1)创建学生情况表(xsqk.dbf) 表结构如下: 字段名类型宽度小数位索引 null 学号 C 8 姓名 C 8 性别 C 2 专业 C 12 出生日期 D 8 入学分数 N 3 0 团员 L 1 备注 M 4 照片 G 4 ①在D盘创建学生管理文件夹,选择“工具/选项/文件位置”把该文件夹设为VFP的默认工作目录。 ②选择“文件/新建/表/新建文件”,在“创建”对话框中的输入表名文本框输入“xsqk”,单击“保存”按钮。 ③进入图1所示的表设计器,依次设置表的所有字段名字、类型、宽度和小数位数。最后单击“确定”按钮。 ④系统提示现在录入记录吗,单击“是”,录入下面两条记录。 ⑤录入两条记录完毕,选择“显示/浏览…”命令查看录入的两条记录。

⑥ 选择“查看/追加方式”命令,继续输入以下三条记录。 ⑦ 选择“显示/表设计器”命令,或在命令窗口输入“MODIFY STRUCTURE ”,打开表设计器,修改表结构,在性别后加一字段籍贯(c,20)。 (2)创建课程表(kc.dbf ) ① 表结构如下: 字段名 类型 宽度 小数位 索引 null 课程号 C 4 课程名 C 12 学分 N 1 0 先修课 C 10 ② 表结构建立完毕,输入以下记录: (3)创建成绩表(cj.dbf ) ① 表结构如下: 字段名 类型 宽度 小数位 索引 null 学号 C 8 课程号 C 4 学期 C 1 图1 表设计器

单链表操作实验报告

线性表 一、实验目的 1. 了解线性表的逻辑结构特征,以及这种特性在计算机内的两种存储结构。 2. 掌握线性表的顺序存储结构的定义及其C语言实现。 3. 掌握线性表的链式村粗结构——单链表的定义及其C语言实现。 4. 掌握线性表在顺序存储结构即顺序表中的各种基本操作。 5. 掌握线性表在链式存储结构——单链表中的各种基本操作。 二、实验要求 1. 认真阅读和掌握本实验的程序。 2. 上机运行本程序。 ) 3. 保存和打印出程序的运行结果,并结合程序进行分析。 4. 按照对顺序表和单链表的操作需要,重新改写主程序并运行,打印出文件清单和运行结果 三、实验内容 请编写C程序,利用链式存储方式来实现线性表的创建、插入、删除和查找等操作。具体地说,就是要根据键盘输入的数据建立一个单链表,并输出该单链表;然后根据屏幕菜单的选择,可以进行数据的插入或删除,并在插入或删除数据后,再输出单链表;然后在屏幕菜单中选择0,即可结束程序的运行。 四、解题思路 本实验要求分别写出在带头结点的单链表中第i(从1开始计数)个位置之后插入元素、创建带头结点的单链表中删除第i个位置的元素、顺序输出单链表的内容等的算法。 五、程序清单 #include<> #include<> #include<> typedef int ElemType; ~ typedef struct LNode { ElemType data; struct LNode *next; }LNode; LNode *L; LNode *creat_L(); void out_L(LNode *L); void insert_L(LNode *L,int i,ElemType e); ElemType delete_L(LNode *L,int i); int locat_L(LNode *L,ElemType e); $

相关文档
最新文档