数据结构实验C语言实现散列表
数据结构实验-实验指导书
实验一线性表操作一、实验目的1熟悉并掌握线性表的逻辑结构、物理结构。
2熟悉并掌握顺序表的存储结构、基本操作和具体的函数定义。
3熟悉VC++程序的基本结构,掌握程序中的用户头文件、实现文件和主文件之间的相互关系及各自的作用。
4熟悉VC++操作环境的使用以及多文件的输入、编辑、调试和运行的全过程。
二、实验要求1实验之前认真准备,编写好源程序。
2实验中认真调试程序,对运行结果进行分析,注意程序的正确性和健壮性的验证。
3不断积累程序的调试方法。
三、实验内容基本题:1对元素类型为整型的顺序存储的线性表进行插入、删除和查找操作。
加强、提高题:2、编写一个求解Josephus问题的函数。
用整数序列1, 2, 3, ……, n表示顺序围坐在圆桌周围的人。
然后使用n = 9, s = 1, m = 5,以及n = 9, s = 1, m = 0,或者n = 9, s = 1, m = 10作为输入数据,检查你的程序的正确性和健壮性。
最后分析所完成算法的时间复杂度。
定义JosephusCircle类,其中含完成初始化、报数出圈成员函数、输出显示等方法。
(可以选做其中之一)加强题:(1)采用数组作为求解过程中使用的数据结构。
提高题:(2)采用循环链表作为求解过程中使用的数据结构。
运行时允许指定任意n、s、m数值,直至输入n = 0退出程序。
实验二栈、队列、递归应用一、实验目的1熟悉栈、队列这种特殊线性结构的特性2熟练掌握栈、队列在顺序存储结构和链表存储结构下的基本操作。
二、实验要求1实验之前认真准备,编写好源程序。
2实验中认真调试程序,对运行结果进行分析,注意程序的正确性和健壮性的验证。
3不断积累程序的调试方法。
三、实验内容基本题(必做):1分别就栈的顺序存储结构和链式存储结构实现栈的各种基本操作。
2、假设以带头结点的循环链表表示队列,并且只设一个指针指向对尾结点,不设头指针,试设计相应的置队空、入队和出队的程序。
加强题:3设线性表A中有n个字符,试设计程序判断字符串是否中心对称,例如xyzyx和xyzzyx都是中心对称的字符串。
数据结构与算法实验报告5-查找与排序
北京物资学院信息学院实验报告
课程名_数据结构与算法
实验名称查找与排序
实验日期年月日实验报告日期年月日姓名______ ___ 班级_____ ________ 学号___
一、实验目的
1.掌握线性表查找的方法;
2.了解树表查找思想;
3.掌握散列表查找的方法.
4.掌握插入排序、交换排序和选择排序的思想和方法;
二、实验内容
查找部分
1.实现顺序查找的两个算法(P307), 可以完成对顺序表的查找操作, 并根据查到和未查到两种情况输出结果;
2.实现对有序表的二分查找;
3.实现散列查找算法(链接法),应能够解决冲突;
排序部分
4.分别实现直接插入排序、直接选择排序、冒泡排序和快速排序算法
三、实验地点与环境
3.1 实验地点
3.2实验环境
(操作系统、C语言环境)
四、实验步骤
(描述实验步骤及中间的结果或现象。
在实验中做了什么事情, 怎么做的, 发生的现象和中间结果, 给出关键函数和主函数中的关键段落)
五、实验结果
六、总结
(说明实验过程中遇到的问题及解决办法;个人的收获;未解决的问题等)。
C语言数据结构线性表的基本操作实验报告
实验一线性表的基本操作一、实验目的与基本要求1.掌握数据结构中的一些基本概念。
数据、数据项、数据元素、数据类型和数据结构,以及它们之间的关系。
2.了解数据的逻辑结构和数据的存储结构之间的区别与联系;数据的运算与数据的逻辑结构的关系。
3.掌握顺序表和链表的基本操作:插入、删除、查找以及表的合并等运算。
4.掌握运用C语言上机调试线性表的基本方法。
二、实验条件1.硬件:一台微机2.软件:操作系统和C语言系统三、实验方法确定存储结构后,上机调试实现线性表的基本运算。
四、实验内容1.建立顺序表,基本操作包括:初始化,建立一个顺序存储的链表,输出顺序表,判断是否为空,取表中第i个元素,定位函数(返回第一个与x相等的元素位置),插入,删除。
2.建立单链表,基本操作包括:初始化,建立一个链式存储的链表,输出顺序表,判断是否为空,取表中第i个元素,定位函数(返回第一个与x相等的元素位置),插入,删除。
3.假设有两个按数据元素值非递减有序排列的线性表A和B,均以顺序表作为存储结构。
编写算法将A表和B表归并成一个按元素值非递增有序(允许值相同)排列的线性表C。
(可以利用将B中元素插入A中,或新建C表)4.假设有两个按数据元素值非递减有序排列的线性表A和B,均以单链表作为存储结构。
编写算法将A表和B表归并成一个按元素值递减有序(即非递增有序,允许值相同)排列的线性表C。
五、附源程序及算法程序流程图1.源程序(1)源程序(实验要求1和3)#include<stdio.h>#include<malloc.h>#include<stdlib.h>#define LIST_INIT_SIZE 100#define LISTINCREMENT 10typedef struct arr{int * elem;int length;int listsize;}Sqlist;void menu(); //菜单void InitList(Sqlist *p); // 创建线性表void ShowList(Sqlist *p); // 输出顺序线性表void ListDelete(Sqlist *p,int i,int &e); // 在顺序线性表中删除第i个元素,并用e返回其值void ListInsert(Sqlist *p); // 在顺序线性表中第i个元素前插入新元素evoid ListEmpty(Sqlist *p); // 判断L是否为空表void GetList(Sqlist *p,int i,int &e); // 用e返回L中第i个数据元素的值void ListInsert(Sqlist *p,int i,int e);bool compare(int a,int b);void LocateElem(Sqlist *L,int e); // 在顺序线性表L中查找第1个值与e满足compare()d元素的位序void MergeList_L(Sqlist *La,Sqlist *Lb); // 归并void main(){Sqlist La;Sqlist Lb;int n,m,x;menu();scanf("%d",&n);while(n){switch(n){case 0: ; break;case 1:InitList(&La);break;case 2:ListEmpty(&La);break;case 3:printf("请输入插入的位序:\n");scanf("%d",&m);printf("请出入要插入的数:\n");scanf("%d",&x);ListInsert(&La,m,x);break;case 4:printf("请输入删除元素的位序:\n");scanf("%d",&m);ListDelete(&La,m,x);printf("删除的元素为:%d\n",x);break;case 5:printf("请输入要找的与线性表中相等的数:\n");scanf("%d",&m);LocateElem(&La,m);break;case 6:printf("请输入查找的位序:\n");scanf("%d",&m);GetList(&La,m,x);printf("La中第%d个元素的值为%d\n",m,x);break;case 7:ShowList(&La);break;case 8:InitList(&Lb);break;case 9:MergeList_L(&La,&Lb);printf("归并成功!");break;}menu();scanf("%d",&n);}}/*菜单*/void menu(){printf("********************\n\n");printf(" 0.退出\n\n");printf(" 1.创建线性表La\n\n");printf(" 2.判断La是否为空表\n\n");printf(" 3.插入元素(La)\n\n");printf(" 4.删除元素(La)\n\n");printf(" 5.定位元素(La)\n\n");printf(" 6.取元素(La)\n\n");printf(" 7.输出线性表\n\n");printf(" 8.创建线性表Lb\n\n");printf(" 9.归并为一个线性表La\n\n");printf("********************\n\n");}/*创建顺序线性表L*/void InitList(Sqlist *L){int n;int i=0;L->elem=(int *)malloc(LIST_INIT_SIZE*sizeof(int));if(NULL==L->elem)printf("储存分配失败!\n");else{L->length=0;L->listsize=LIST_INIT_SIZE;printf("输入顺序表a:\n");scanf("%d",&n);while(n){L->elem[i]=n;i++;L->length++;L->listsize=L->listsize-4;scanf("%d",&n);}}}/*输出顺序线性表*/void ShowList(Sqlist *p){int i;if(0==p->length)printf("数组为空!\n");elsefor(i=0;i<p->length;i++)printf("%d ",p->elem[i]);printf("\n");}/*判断L是否为空表*/void ListEmpty(Sqlist *p)if(0==p->length)printf("L是空表!\n");elseprintf("L不是空表!\n");}/*在顺序线性表中第i个元素前插入新元素e */void ListInsert(Sqlist *p,int i,int e){int *newbase;int *q1;int *q2;while(i<1||i>p->length+1){printf("您输入的i超出范围!\n请重新输入要插入的位置\n:");scanf("%d",&i);}if(p->length>=p->listsize){newbase=(int *)realloc(p->elem,(p->listsize+LISTINCREMENT)*sizeof(int));if(!newbase)exit(0);else{p->elem=newbase;p->listsize+=LISTINCREMENT;}}q1=&(p->elem[i-1]);for(q2=&(p->elem[p->length-1]);q2>=q1;--q2)*(q2+1)=*q2;*q1=e;++p->length;}/*/在顺序线性表中删除第i个元素,并用e返回其值*/void ListDelete(Sqlist *p,int i,int &e){int *q1,*q2;while(i<1||i>p->length){printf("您输入的i超出范围!请重新输入:");scanf("%d",&i);}q1=&(p->elem[i-1]);e=*q1;q2=p->elem+p->length-1;for(++q1;q1<=q2;++q1)*(q1-1)=*q1;--p->length;}/*对比a与b相等*/bool compare(int a,int b){if(a==b)return 1;elsereturn 0;}/*在顺序线性表L中查找第1个值与e满足compare()d元素的位序*/ void LocateElem(Sqlist *L,int e){int i=1;int *p;p=L->elem;while(i<=L->length && !compare(*p++,e))++i;if(i<=L->length)printf("第1个与e相等的元素的位序为%d\n",i);elseprintf("没有该元素!\n");}/*用e返回L中第i个数据元素的值*/void GetList(Sqlist *p,int i,int &e){Sqlist *p1;p1=p;e=p1->elem[i-1];}/* 已知顺序线性表La和Lb是元素按值非递减排列*//* 把La和Lb归并到La上,La的元素也是按值非递减*/void MergeList_L(Sqlist *La,Sqlist *Lb){int i=0,j=0,k,t;int *newbase;Sqlist *pa,*pb;pa=La;pb=Lb;while(i<pa->length && j<pb->length){if(pa->elem[i] >= pb->elem[j]){if(pa->listsize==0){newbase=(int*)realloc(pa->elem,(pa->listsize+LISTINCREMENT)*sizeof(int));if(!newbase)exit(0);}for(k=pa->length-1; k>=i; k--)pa->elem[k+1]=pa->elem[k];pa->length++;pa->elem[i]=pb->elem[j];i++;j++;}elsei++;}while(j<pb->length){if( pa->listsize < pb->length-j ){newbase=(int*)realloc(pa->elem,(pa->listsize+LISTINCREMENT)*sizeof(int));if(!newbase)exit(0);}for(j;j<pb->length;j++,i++){pa->elem[i]=pb->elem[j];pa->length++;}}for(i=0;i<pa->length/2;i++){t=pa->elem[i];pa->elem[i]=pa->elem[pa->length-i-1];pa->elem[pa->length-i-1]=t;}}(2)源程序(实验要求2和4)#include<stdio.h>#include<malloc.h>#include<stdlib.h>typedef struct LNode{int data;struct LNode *next;}LNode, *LinkList;void menu();LinkList InitList();void ShowList(LinkList L);void ListDelete(LinkList L,int i,int &e);void ListEmpty(LinkList L);void GetList(LinkList L,int i,int &e);void ListInsert(LinkList L,int i,int e);bool compare(int a,int b);void LocateElem(LinkList L,int e);LinkList MergeList_L(LinkList La,LinkList Lb);int total=0;void main(){LinkList La;LinkList Lb;La=(LinkList)malloc(sizeof(struct LNode));La->next=NULL;Lb=(LinkList)malloc(sizeof(struct LNode));Lb->next=NULL;int n;int m;int x;menu();scanf("%d",&n);while(n){switch(n){case 0: ; break;case 1:La->next=InitList();break;case 2:ListEmpty(La);break;case 3:printf("请输入要插入到第几个节点前:\n");scanf("%d",&m);printf("请输入插入的数据:\n");scanf("%d",&x);ListInsert(La,m,x);break;case 4:printf("请输入删除元素的位序:\n");scanf("%d",&m);ListDelete(La,m,x);printf("删除的元素为:%d\n",x);break;case 5:printf("请输入要找的与线性表中相等的数:\n");scanf("%d",&m);LocateElem(La,m);break;case 6:printf("请输入查找的位序:\n");scanf("%d",&m);GetList(La,m,x);printf("La中第%d个元素的值为%d\n",m,x);break;case 7:ShowList(La);break;case 8:Lb->next=InitList();break;case 9:La=MergeList_L(La,Lb);printf("归并成功\n");break;}menu();scanf("%d",&n);}}void menu(){printf("********************\n\n");printf(" 0.退出\n\n");printf(" 1.创建线性表La\n\n");printf(" 2.判断是否为空表\n\n");printf(" 3.插入元素\n\n");printf(" 4.删除元素\n\n");printf(" 5.定位元素\n\n");printf(" 6.取元素\n\n");printf(" 7.输出线性表\n\n");printf(" 8.创建线性表Lb\n\n");printf(" 9.归并两线性表\n\n");printf("********************\n\n");}// 创建链式线性表LLinkList InitList(){int count=0;LinkList pHead=NULL;LinkList pEnd,pNew;pEnd=pNew=(LinkList)malloc(sizeof(struct LNode));printf("请输入数据:\n");scanf("%d",&pNew->data);while(pNew->data){count++;if(count==1){pNew->next=pHead;pEnd=pNew;pHead=pNew;}else{pNew->next=NULL;pEnd->next=pNew;pEnd=pNew;}pNew=(LinkList)malloc(sizeof(struct LNode));printf("请输入数据:\n");scanf("%d",&pNew->data);}free(pNew);total=total+count;return pHead;}// 判断L是否为空表void ListEmpty(LinkList L){if(NULL==L->next)printf("此表为空表!\n");elseprintf("此表不为空表!\n");}// 在链式线性表中第i个元素前插入新元素e void ListInsert(LinkList L,int i,int e){LinkList p;LinkList s;p=L;int j=0;while(p&&j<i-1){p=p->next;++j;}if(!p||j>i-1)printf("不存在您要找的节点!\n");else{s=(LinkList)malloc(sizeof(int));s->data=e;s->next=p->next;p->next=s;printf("插入节点成功!\n");}}// 输出链式线性表void ShowList(LinkList L){LinkList p;p=L->next;if(p==NULL)printf("此表为空表!\n");elsewhile(p){printf("%d ",p->data);p=p->next;}printf("\n");}// 在链式线性表中删除第i个元素,并用e返回其值void ListDelete(LinkList L,int i,int &e){LinkList p;LinkList q;p=L;int j=0;while(p->next && j<i-1){p=p->next;++j;}if(!(p->next)||j>i-1)printf("没有找到要删除的位置!");else{q=p->next;p->next=q->next;e=q->data;free(q);}}// 用e返回L中第i个数据元素的值void GetList(LinkList L,int i,int &e){LinkList p;p=L->next;int j=0;while(p->next && j<i-1){p=p->next;++j;}if(!(p)||j>i-1)printf("没有找到要查找的位置!");elsee=p->data;}// 对比a与b相等bool compare(int a,int b){if(a==b)return 1;elsereturn 0;}// 在链式线性表L中查找第1个值与e满足compare()d元素的位序void LocateElem(LinkList L,int e){int i=0;LinkList p;p=L;while(p->next && !compare(p->data,e)){p=p->next;i++;}if(NULL==p->next){if(0==compare(p->data,e))printf("没有该元素!\n");elseprintf("第1个与e相等的元素的位序为%d\n",i);}elseif(compare(p->data,e))printf("没有该元素!\n");}LinkList MergeList_L(LinkList La,LinkList Lb){int i,j,k;LinkList pa_1,pb_1,pa_2,pb_2,pc,pd;pa_1=La->next;pc=pa_2=La;pb_1=pb_2=Lb->next;if(pa_1->data > pb_1->data){pc=pa_2=Lb;pa_1=Lb->next;pb_1=pb_2=La->next;}while(pa_1 && pb_1){if(pa_1->data >= pb_1->data){pa_2->next=pb_1;pb_2=pb_1->next;pb_1->next=pa_1;pb_1=pb_2;pa_2=pa_2->next;}else{pa_1=pa_1->next;pa_2=pa_2->next;}}if(pb_1)pa_2->next=pb_1;pd=(LinkList)malloc(sizeof(struct LNode));pd->next=NULL;pa_2=pd;k=total;for(i=0;i<total;i++){pa_1=pc->next;for(j=1;j<k;j++)pa_1=pa_1->next;pb_1=(LinkList)malloc(sizeof(struct LNode));pa_2->next=pb_1;pa_2=pa_2->next;pa_2->data=pa_1->data;k--;}pa_2->next=NULL;return pd;}2.流程图(实验要求1和3)图1 主函数流程图图2创建线性表La流程图图3判断La是否为空表流程图图4 插入元素(La)流程图图5删除元素(La)流程图图6定位元素(La)流程图图7取元素(La)流程图图8输出线性表流程图图9输出线性表流程图流程图(实验要求2和4)图10主函数流程图图11创建线性表La流程图图12判断是否为空表流程图图13插入元素流程图图14删除元素流程图图15定位元素流程图图图16取元素流程图图17创建Lb流程图图18归并两表流程图六、运行结果1. (实验要求1和3)点击运行,首先出现的是菜单界面,选择菜单选项进行操作,如图所示。
c实现的hash表-概述说明以及解释
c实现的hash表-概述说明以及解释1.引言1.1 概述在计算机科学中,哈希表(Hash Table),又被称为散列表,是一种常用的数据结构。
它能够以常数时间复杂度(O(1))来实现插入、删除和查找等操作,因此具有高效的特性。
哈希表通过哈希函数将键(key)映射到一个固定大小的数组(通常称为哈希表)。
通过这种映射关系,我们可以在数组中快速访问到对应的值(value)。
常见的应用场景包括缓存系统、数据库索引、编译器符号表等。
相对于其他数据结构,哈希表具有以下优点:1. 高效的插入、删除和查找操作:哈希表在插入、删除和查找数据时以常数时间复杂度进行操作,无论数据量大小,都能快速地完成操作。
2. 高效的存储和检索:通过哈希函数的映射关系,哈希表能够将键值对存储在数组中,可以通过键快速地找到对应的值。
3. 空间效率高:哈希表通过哈希函数将键映射到数组下标,能够充分利用存储空间,避免冗余的存储。
然而,哈希表也存在一些局限性:1. 冲突问题:由于哈希函数的映射关系是将多个键映射到同一个数组下标上,可能会导致冲突。
解决冲突问题的常见方法包括链地址法(Chaining)和开放定址法(Open Addressing)等。
2. 内存消耗:由于哈希表需要维护额外的空间来存储映射关系,所以相比于其他数据结构来说,可能会占用较多的内存。
本篇长文将重点介绍C语言实现哈希表的方法。
我们将首先讨论哈希表的定义和实现原理,然后详细介绍在C语言中如何实现一个高效的哈希表。
最后,我们将总结哈希表的优势,对比其他数据结构,并展望哈希表在未来的发展前景。
通过本文的学习,读者将能够深入理解哈希表的底层实现原理,并学会如何在C语言中利用哈希表解决实际问题。
1.2 文章结构本文将围绕C语言实现的hash表展开讨论,并按照以下结构进行组织。
引言部分将对hash表进行概述,介绍hash表的基本概念、作用以及其在实际应用中的重要性。
同时,引言部分还会阐述本文的目的,即通过C语言实现的hash表,来探讨其实现原理、方法以及与其他数据结构的对比。
c语言版数据结构试题及答案
习题一一、单选题1.在一个带有附加表头结点的单链表HL中,若要向表头插入一个由指针p指向的结点,则执行( B )。
A. HL=p; p->next=HL;B. p->next=HL->next; HL->next=p;C. p->next=HL; p=HL;D. p->next=HL; HL=p;2.若顺序存储的循环队列的QueueMaxSize=n,则该队列最多可存储( B )个元素.A. nB.n-1C. n+1D.不确定3.下述哪一条是顺序存储方式的优点?(A )A.存储密度大 B.插入和删除运算方便C. 获取符合某种条件的元素方便D.查找运算速度快4.设有一个二维数组A[m][n],假设A[0][0]存放位置在600(10),A[3][3]存放位置在678(10),每个元素占一个空间,问A[2][3](10)存放在什么位置?(脚注(10)表示用10进制表示,m>3)DA.658 B.648 C.633 D.6535.下列关于二叉树遍历的叙述中,正确的是( AD ) 。
A. 若一个树叶是某二叉树的中序遍历的最后一个结点,则它必是该二叉树的前序遍历最后一个结点B.若一个点是某二叉树的前序遍历最后一个结点,则它必是该二叉树的中序遍历的最后一个结点 C.若一个结点是某二叉树的中序遍历的最后一个结点,则它必是该二叉树的前序最后一个结点D.若一个树叶是某二叉树的前序最后一个结点,则它必是该二叉树的中序遍历最后一个结点6.k层二叉树的结点总数最多为( A ).A.2k-1 B.2K+1 C.2K-1 D. 2k-17.对线性表进行二分法查找,其前提条件是( B ).A.线性表以链接方式存储,并且按关键码值排好序B.线性表以顺序方式存储,并且按关键码值的检索频率排好序C.线性表以顺序方式存储,并且按关键码值排好序D.线性表以链接方式存储,并且按关键码值的检索频率排好序8.对n个记录进行堆排序,所需要的辅助存储空为Cn) B. O(n) C. O(1) D. O(n2)A. O(1og29.对于线性表(7,34,77,25,64,49,20,14)进行散列存储时,若选用H(K)=K %7作为散列函数,则散列地址为0的元素有( D )个,A.1 B.2 C.3 D.410.下列关于数据结构的叙述中,正确的是( D ).A.数组是不同类型值的集合B.递归算法的程序结构比迭代算法的程序结构更为精炼C.树是一种线性结构D.用一维数组存储一棵完全二叉树是有效的存储方法二、填空题1.数据的逻辑结构被分为_集合结构、__线性结构、_树结构和_图结构四种。
数据结构课程设计-利用散列表做一个电话号码查找系统
数据结构课程设计-利⽤散列表做⼀个电话号码查找系统【基本要求】(1)设每个记录有下列数据项:电话号码、⽤户名、地址;(2)从键盘输⼊各记录,分别以电话号码和⽤户名为关键字建⽴散列表;(3)采⽤⼀定的⽅法解决冲突;(4)查找并显⽰给定电话号码的记录;(5)查找并显⽰给定⽤户名的记录。
【选做内容】(1)系统功能的完善;(2)设计不同的散列函数,⽐较冲突率; (3)在散列函数确定的前提下,尝试各种不同类型处理冲突的⽅法,考察平均查找长度的变化。
⽤的C++开发,基本实现了3种哈希函数+3种解决冲突的⽅法。
因为要求同时有姓名散列与按号码散列,所以⽤了flag标记每次的散列类型,针对不同的要求对散列函数做了个别优化。
哈希表类的结构如下1class HashTable{2public:3 HashTable(int size = MAXSIZE-1);4 ~HashTable(){ delete[]E; delete[]tag; delete[]E2; delete[]tag2; }5int hash1(string name, int flag);//哈希函数1 除数求余法6int hash2(string tel);//哈希函数2 折叠法7int hash3(string tel);//哈希函数3 数字分析法8int solve1(int hashVal, int flag);//线性探测法解决冲突9int solve2(int hashVal, int flag);//⼆次探测法解决冲突10 Node* solve3(int hashVal, int flag);//拉链法解决冲突11 User input();//往电话薄中添加⽤户12void creat(int flag); //创建散列表13void show(int flag); //列出电话薄所有元素14void search(int flag,string at); //搜索指定⽤户15void searchByNode(int flag, string at); //拉链法搜索指定⽤户16void insert(int flag, User newUser); //插⼊17void del(int flag, string by);//删除18void save(int flag);//将电话薄保存⾄本地⽂件19int length; //要创建的电话本长度20 Node** ht;21private:22 User* E; //⽤户数组按姓名散列23 User* E2; //⽤户数组2 按电话号码散列24int* tag; //标记散列表1每个桶的存储状态 0为空 1为实25int* tag2;//标记散列表2每个桶的存储状态26int flag; //1表⽰是按姓名 2表⽰按电话号码新建的哈希表27int maxSize; //哈希表最⼤长度28int f;//⽐例因⼦主要⽤于折叠法29 };View CodeUser类的结构class User{public:string name;string tel;string address;bool operator==(const User&target){if (this->name == &&this->address == target.address&&this->tel == target.tel)return true;elsereturn false;}};哈希函数1int HashTable::hash1(string name,int flag) //除留求余法{int hashValue; long a = 0;switch (flag){case1:for (int i = 0; i < name.length(); i++)a += int(name[i]);hashValue = a%maxSize;break;case2:int temp = atof(name.c_str());hashValue = temp%maxSize;break;}return hashValue;};哈希函数2int HashTable::hash2(string tel) //折叠法--移位法{int hashValue;int temp; //移位法求和temp = atof(tel.substr(0, 3).c_str()) + atof(tel.substr(3, 3).c_str())+ atof(tel.substr(6, 3).c_str()) + atof(tel.substr(9, 2).c_str());//取计算之后的数的最后三位if (temp >= 999){char p[10];sprintf(p, "%d", temp);string lastThree = p;lastThree = lastThree.substr(lastThree.length() - 3, 3);hashValue = atof(lastThree.c_str());return hashValue;}hashValue = temp;return hashValue;};哈希函数3int HashTable::hash3(string tel)//数字分析法做哈希函数{int hashValue;hashValue = atof(tel.substr(8, 3).c_str()); //因为电话号码⼀般后4位不同return hashValue;};解决冲突的⽅法1.线性探测法int HashTable::solve1(int hashVal,int flag) //线性探查法处理冲突{int output = hashVal;switch (flag){case1:for (int j = 1; j < MAXSIZE; j++){output = (hashVal + j) % MAXSIZE;if (tag[output] == 0){tag[output] = 1;return output;}}return -1;break;case2:for (int j = 1; j < MAXSIZE; j++){output = (hashVal + j) % MAXSIZE;if (tag2[output] == 0){tag2[output] = 1;return output;}}return -1;default:break;}};2.⼆次探查法int HashTable::solve2(int hashVal, int flag) //⼆次探查法解决冲突{int i = hashVal; //i为初始桶号int k = 0; //k为探查次数int odd = 0; //odd为控制加减的标志int save; //缓存上⼀次的桶号switch (flag){case1:while (tag[i]==1){if (odd == 0){k++; save = i;i = (i + 2 * k-1) % MAXSIZE;odd = 1;}else{i = (save - 2 * k+1) % MAXSIZE;odd = 0;if (i<0){i = i + MAXSIZE;}}}return i;break;case2:while (tag2[i] == 1){if (odd == 0){k++; save = i;i = (i + 2 * k - 1) % MAXSIZE;odd = 1;}else{k++;i = (save - 2 * k + 1) % MAXSIZE;odd = 0;if (i<0){i = i + MAXSIZE;}}}return i;break;default:break;}};3.拉链法Node* HashTable::solve3(int hashVal, int flag)//拉链法解决冲突{int i = hashVal; //第i条链Node*p = ht[i]; //该链上的头指针while (p!=NULL)p = p->next;//往后遍历直到找到⼀个空节点⽤于存放userreturn p;};所有代码如下1 #include <iostream>2 #include <string>3 #include <fstream>45using namespace std;67const int MAXSIZE = 12;//默认最⼤表长89101112//存储项13class User{14public:15string name;16string tel;17string address;18bool operator==(const User&target)19 {20if (this->name == &&this->address == target.address&&this->tel == target.tel) 21return true;22else23return false;24 }25 };2627//⽤于拉链法28struct Node{29 User user;30 Node* next;31 };32class HashTable{33public:34 HashTable(int size = MAXSIZE-1);35 ~HashTable(){ delete[]E; delete[]tag; delete[]E2; delete[]tag2; }36int hash1(string name, int flag);//哈希函数1 除数求余法37int hash2(string tel);//哈希函数2 折叠法38int hash3(string tel);//哈希函数3 数字分析法39int solve1(int hashVal, int flag);//线性探测法解决冲突40int solve2(int hashVal, int flag);//⼆次探测法解决冲突41 Node* solve3(int hashVal, int flag);//拉链法解决冲突42 User input();//往电话薄中添加⽤户43void creat(int flag); //创建散列表44void show(int flag); //列出电话薄所有元素45void search(int flag,string at); //搜索指定⽤户46void searchByNode(int flag, string at); //拉链法搜索指定⽤户47void insert(int flag, User newUser); //插⼊48void del(int flag, string by);//删除49void save(int flag);//将电话薄保存⾄本地⽂件50int length; //要创建的电话本长度51 Node** ht;52private:53 User* E; //⽤户数组按姓名散列54 User* E2; //⽤户数组2 按电话号码散列55int* tag; //标记散列表1每个桶的存储状态 0为空 1为实56int* tag2;//标记散列表2每个桶的存储状态57int flag; //1表⽰是按姓名 2表⽰按电话号码新建的哈希表58int maxSize; //哈希表最⼤长度59int f;//⽐例因⼦主要⽤于折叠法60 };6162 HashTable::HashTable(int size)63 {64 maxSize = size; //⽤作除数65 E = new User[MAXSIZE];66 E2 = new User[MAXSIZE];67 tag = new int[MAXSIZE];68 tag2 = new int[MAXSIZE];69for (int i = 0; i < MAXSIZE; i++)70 {71 tag[i] = 0;72 tag2[i] = 0;73 }74 f = maxSize / 512; //⽤于折叠法产⽣的哈希值过⼤保留3位数的地址范围为0~51175 ht = new Node*[maxSize]; //存放节点的⼀维数组拉链法76 };7778int HashTable::hash1(string name,int flag) //除数求余法79 {80int hashValue; long a = 0;81switch (flag)82 {83case1:84for (int i = 0; i < name.length(); i++)85 a += int(name[i]);86 hashValue = a%maxSize;87break;88case2:89int temp = atof(name.c_str());90 hashValue = temp%maxSize;91break;9293 }94return hashValue;95 };9697int HashTable::hash2(string tel) //折叠法--移位法98 {99int hashValue;100int temp; //移位法求和101 temp = atof(tel.substr(0, 3).c_str()) + atof(tel.substr(3, 3).c_str())102 + atof(tel.substr(6, 3).c_str()) + atof(tel.substr(9, 2).c_str());103//取计算之后的数的最后三位104if (temp >= 999)105 {106char p[10];107 sprintf(p, "%d", temp);108string lastThree = p;109 lastThree = lastThree.substr(lastThree.length() - 3, 3);110 hashValue = atof(lastThree.c_str());111return hashValue;112 }113 hashValue = temp;114return hashValue;115 };116117int HashTable::hash3(string tel)//数字分析法做哈希函数118 {119int hashValue;120 hashValue = atof(tel.substr(8, 3).c_str()); //因为电话号码⼀般后4位不同121return hashValue;122 };123124int HashTable::solve1(int hashVal,int flag) //线性探查法处理冲突125 {126int output = hashVal;127switch (flag)128 {129case1:130for (int j = 1; j < MAXSIZE; j++)131 {132 output = (hashVal + j) % MAXSIZE;133if (tag[output] == 0)134 {135 tag[output] = 1;136return output;137 }138 }139return -1;140break;141case2:142for (int j = 1; j < MAXSIZE; j++)143 {144 output = (hashVal + j) % MAXSIZE;145if (tag2[output] == 0)146 {147 tag2[output] = 1;148return output;149 }150 }151return -1;152default:153break;154 }155156 };157158int HashTable::solve2(int hashVal, int flag) //⼆次探查法解决冲突159 {160int i = hashVal; //i为初始桶号161int k = 0; //k为探查次数162int odd = 0; //odd为控制加减的标志163int save; //缓存上⼀次的桶号164switch (flag)165 {166case1:167while (tag[i]==1)168 {169if (odd == 0)170 {171 k++; save = i;172 i = (i + 2 * k-1) % MAXSIZE;173 odd = 1;174 }175else176 {177 i = (save - 2 * k+1) % MAXSIZE;178 odd = 0;179if (i<0)180 {181 i = i + MAXSIZE;182 }183 }184 }185return i;186break;187case2:188while (tag2[i] == 1)189 {190if (odd == 0)191 {192 k++; save = i;193 i = (i + 2 * k - 1) % MAXSIZE;194 odd = 1;195 }196else197 {198 k++;199 i = (save - 2 * k + 1) % MAXSIZE;200 odd = 0;201if (i<0)202 {203 i = i + MAXSIZE;204 }205 }206 }207return i;208break;209default:210break;211 }212213 };214215/*216Node* HashTable::solve3(int hashVal, int flag)//拉链法解决冲突217218{219 int i = hashVal; //第i条链220221 Node*p = ht[i]; //该链上的头指针222 while (p!=NULL)223 p = p->next;//往后遍历直到找到⼀个空节点⽤于存放user 224 return p;225};226227void HashTable::searchByNode(int flag, string at)//调⽤拉链法搜索228{229 int i = hash1(at,1);230 Node** ht = new Node*[maxSize]; //存放节点的⼀维数组231 Node*p = ht[i]; //该链上的头指针232 while (p!=NULL&&p->!=at)233 {234 p = p->next;235 }236};237*/238 User HashTable::input()239 {240 User user;241 cout << "请输⼊姓名:" << endl;242 cin >> ;243 cout << "请输⼊电话号码:" << endl;244 cin >> user.tel;245 cout << "请输⼊地址:" << endl;246 cin >> user.address;247return user;248 };249250void HashTable::creat(int flag)251 {252switch (flag)253 {254case1: //按姓名哈希创建哈希表255for (int i = 0; i < length; i++)256 {257 User newUser = input();258int val = hash1(,1);259if (tag[val] == 1)260 val = solve1(val,1);//线性探测法解决冲突261 E[val] = newUser;262 tag[val] = 1;263 }264break;265case2: //按电话号码哈希创建哈希表266for (int i = 0; i < length; i++)267 {268 User newUser = input();269int val = hash1(newUser.tel,2);270if(tag2[val] == 1)271 val = solve1(val,2);//线性探测法解决冲突272 E2[val] = newUser;273 tag2[val] = 1;274 }275break;276 }277 };278void HashTable::show(int flag)279 {280switch (flag)281 {282case1:283for (int i = 0; i < MAXSIZE; i++)284 {285if (tag[i] == 1)286 cout << E[i].name << "" << E[i].tel << "" << E[i].address << " 位于: " << i << endl; 287 }288break;289case2:290for (int i = 0; i < MAXSIZE; i++)291 {292if (tag2[i] == 1)293 cout << E2[i].name << "" << E2[i].tel << "" << E2[i].address << " 位于: " << i << endl; 294 }295break;296 }297298 };299300void HashTable::search(int flag,string at) //at表⽰索引内容301 {302int i = 0;303switch (flag)304 {305case1: //调⽤线性探测法查找姓名306 i = hash1(at,1);307if (tag[i] == 1 && E[i].name != at)308 i = solve1(i, 2);309if (i < 0 || tag2[i] == 0)310 {311 cout << "查⽆此⼈!" << endl;312return;313 }314if (tag[i] == 1 && E[i].name == at)315 cout << E2[i].name << "" << E2[i].tel << "" << E2[i].address << endl;316break;317case2: //调⽤⼆次探测法查找电话号码318 i = hash2(at);319if (tag2[i] == 1&&E2[i].tel!=at)320 i = solve2(i,2);321if (i < 0||tag2[i]==0)322 {323 cout << "查⽆此⼈!" << endl;324return;325 }326if (tag2[i] == 1 && E2[i].tel==at)327 cout << E2[i].name << "" << E2[i].tel << "" << E2[i].address << endl;328break;329 }330 };331332void HashTable::insert(int flag, User newUser){333int i = -1;334switch (flag)335 {336case1:337 i = hash1(,1);338if (tag[i] == 1||E[i]==newUser)339 i = solve1(i, 1);340if (i < 0)341 {342 cout << "表满!插⼊失败!" << endl;343return;344 }345if (tag[i] == 0)346 {347 E[i] = newUser;348 tag[i] = 1;349 length++;350 cout << "插⼊成功" << endl;351 }352case2:353 i = hash1(newUser.tel,2);354if (tag2[i] == 1 || E2[i] == newUser)355 i = solve1(i, 2);356if (i < 0)357 {358 cout << "表满!插⼊失败!" << endl;359return;360 }361if (tag2[i] == 0)362 {363 E2[i] = newUser;364 tag2[i] = 1;365 length++;366 cout << "插⼊成功" << endl;367 }368default:369break;370 }371 };372373void HashTable::del(int flag, string by) //by表⽰按照何种标签进⾏删除374 {375int i = -1;376int select;//选择是否删除377switch (flag)378 {379case1: //调⽤线性探测法查找姓名380 i = hash1(by,1);381if (tag[i] == 1 && E[i].name != by)382 i = solve1(i, 2);383if (i < 0 || tag2[i] == 0)384 {385 cout << "查⽆此⼈!" << endl;386return;387 }388if (tag[i] == 1 && E[i].name == by)389 {390 cout << E2[i].name << "" << E2[i].tel << "" << E2[i].address << endl; 391 cout << "是否删除 0.删了 1.算了" << endl;392 cin >> select;393if (select == 0)394 tag[i] = 0;//伪删除395 }396break;397case2: //调⽤⼆次探测法查找电话号码398 i = hash2(by);399if (tag2[i] == 1 && E2[i].tel != by)400 i = solve2(i, 2);401if (i < 0 || tag2[i] == 0)402 {403 cout << "查⽆此⼈!" << endl;404return;405 }406if (tag2[i] == 1 && E2[i].tel == by)407 {408 cout << E2[i].name << "" << E2[i].tel << "" << E2[i].address << endl; 409 cout << "是否删除 0.删了 1.算了" << endl;410 cin >> select;411if (select == 0)412 tag2[i] = 0;//伪删除413 }414break;415 }416 };417418void HashTable::save(int flag)419 {420 fstream out1("电话薄(姓名散列).txt", ios::out);421 fstream out2("电话薄(号码散列).txt", ios::out);422switch (flag)423 {424case1:425for (int i = 0; i < maxSize; i++)426 {427if (tag[i] == 1)428 out1 << E[i].name << "" << E[i].tel << "" << E[i].address << endl; 429 }430 cout << "已存⾄电话薄(姓名散列).txt" << endl;431return;432break;433case2:434for (int i = 0; i < maxSize; i++)435 {436if (tag2[i] == 1)437 out2 << E2[i].name << "" << E2[i].tel << "" << E2[i].address << endl; 438 }439 cout << "已存⾄电话薄(号码散列).txt" << endl;440return;441break;442default:443break;444 }445446 };hashtable.h1 #include <iostream>2 #include <string>3 #include <fstream>4 #include "hashtable.h"5using namespace std;67//菜单8void menu()9 {10 cout << " ****************************" << endl;11 cout << "|| 0.建表 ||" << endl;12 cout << "|| 1.查看 ||" << endl;13 cout << "|| 2.搜索 ||" << endl;14 cout << "|| 3.添加 ||" << endl;15 cout << "|| 4.删除 ||" << endl;16 cout << "|| 5.保存 ||" << endl;17 cout << "|| 6.退出 ||" << endl;18 cout << " ****************************" << endl;1920 }2122int main()23 {24 User user;25int size;//第⼀次创建的数据量⼤⼩26int select;//主菜单选项27int select_;//⼦菜单选项28 cout << "欢迎使⽤电话簿" << endl;29 HashTable ht;30while (1)31 {32 menu();33 cin >> select;34switch (select)35 {36case0:37 cout << "第⼀次使⽤,请输⼊要新建的电话本⼤⼩:" << endl;38 cin >> size;39 ht.length = size;40 cout << "1.姓名散列 2.电话号码散列" << endl;41 cin >> select_;42 ht.creat(select_);43break;44case1:45 cout << "1.姓名散列 2.电话号码散列" << endl;46 cin >> select_;47 ht.show(select_);48break;49case2:50 cout << "1.按姓名查找 2.按电话号码查找" << endl;51 cin >> select_;52if (select_==1)53 {54 cout << "输⼊姓名" << endl;55string name;56 cin >> name;57 ht.search(1, name);58 }59else if (select_ == 2)60 {61 cout << "输⼊号码" << endl;62string tel;63 cin >> tel;64 ht.search(2, tel);65 }66else67 cout << "不合法操作" << endl;68break;69case3:70 user = ht.input();71 cout << "1.插⼊到姓名散列表 2.插⼊到电话号码散列" << endl;72 cin >> select_;73 ht.insert(select_,user);74break;75case4:76 cout << "1.根据姓名删除 2.根据电话号码删除" << endl;77 cin >> select_;78if (select_ == 1)79 {80 cout << "输⼊姓名" << endl;81string name;82 cin >> name;83 ht.del(1, name);84 }85else if (select_ == 2)86 {87 cout << "输⼊号码" << endl;88string tel;89 cin >> tel;90 ht.del(2, tel);91 }92else93 cout << "不合法操作" << endl;94break;95case5:96 cout << "1.保存姓名散列表到本地 2.保存电话号码散列表到本地" << endl;97 cin >> select_;98 ht.save(select_);99case6:100return0;101 }102 }103 }main.cpp通过这次课程设计,总结如下1. C++技艺不精,语法不熟悉,⽐如模版类与运算符重载,指针更是不⼤熟练。
2015实验报告模板
实验报告模板填写说明1、出现的红色部分请填写,并将红色文字删除2、算法描述是以老师建议的算法简要描述的,如果和你的实现方案或者细节不一致的,请自行修改描述。
3、在实验结果中粘贴真实测试结果截图,不必是100分,这个不作为最终实验评分依据,如:贵州大学计算机科学与技术学院计算机科学与技术系上机实验报告贵州大学计算机科学与技术学院计算机科学与技术系上机实验报告课程名称:数据结构班级:计科132实验日期:4月6日姓名:姓名学号:XXX指导教师:程欣宇实验序号:二实验成绩:一、实验名称栈与其应用二、实验目的与要求1、熟悉栈的原理和实现方式;2、掌握利用栈解决列车调度问题三、实验环境任何一种C++编写调试工具 + 清华数据结构Online Judge四、实验内容完成PA02的列车调度这道题五、算法描述与实验步骤列车调度问题是求解一个已知的顺序序列A,是否能够通过一个容量最大为m的栈S,调度为希望的序列B,如图:算法框架如下:贵州大学计算机科学与技术学院计算机科学与技术系上机实验报告贵州大学计算机科学与技术学院计算机科学与技术系上机实验报告贵州大学计算机科学与技术学院计算机科学与技术系上机实验报告贵州大学计算机科学与技术学院计算机科学与技术系上机实验报告贵州大学计算机科学与技术学院计算机科学与技术系上机实验报告3、从小顶堆中取出最小元素后,可以在log(n)的时间内恢复为小顶堆。
4、任意一个元素,可以在log(n)的时间内插入小顶堆。
最小堆物理结构最小堆逻辑结构在本题中,队列元素出队后,还会再入队,我们可以得出算法流程大致如下:初始化有些队列PQ,队列元素为字符串与其优先级读入参数n,m循环n次,读取每个元素,插入队列PQ,花费O(nlogn)建堆循环m次每次输出堆顶元素e将e乘以2以后再次入队实验步骤1、阅读PA04的任务调度这道题;2、采用小顶堆实现优先队列,建议实现为模板类;贵州大学计算机科学与技术学院计算机科学与技术系上机实验报告。
(完整版)设计散列表实现通讯录查找系统
设计散列表实现通讯录查找系统#include<stdio.h>#include<stdlib.h>#include<string>#include <windows.h>#define MAXSIZE 20 //电话薄记录数量#define MAX_SIZE 20 //人名的最大长度#define HASHSIZE 53 //定义表长#define SUCCESS 1#define UNSUCCESS -1#define LEN sizeof(HashTable)typedef int Status;typedef char NA[MAX_SIZE];typedef struct{//记录NA name;NA tel;NA add;}Record;typedef struct{//哈希表Record *elem[HASHSIZE]; //数据元素存储基址int count; //当前数据元素个数int size; //当前容量}HashTable;Status eq(NA x,NA y){//关键字比较,相等返回SUCCESS;否则返回UNSUCCESS if(strcmp(x,y)==0)return SUCCESS;else return UNSUCCESS;}Status NUM_BER; //记录的个数void getin(Record* a){//键盘输入各人的信息printf("输入要添加的个数:\n");scanf("%d",&NUM_BER);for(i=0;i<NUM_BER;i++){printf("请输入第%d个记录的用户名:\n",i+1);scanf("%s",a[i].name);printf("请输入%d个记录的电话号码:\n",i+1);scanf("%s",a[i].tel);printf("请输入第%d个记录的地址:\n",i+1);scanf("%s",a[i].add); //gets(str2);??????}}void ShowInformation(Record* a)//显示输入的用户信息{int i;for( i=0;i<NUM_BER;i++)printf("\n第%d个用户信息:\n 姓名:%s\n 电话号码:%s\n 联系地址:% s\n",i+1,a[i].name,a[i].tel,a[i].add);}void Cls(Record* a){printf("*");system("cls");}long fold(NA s){//人名的折叠处理char *p;long sum=0;NA ss;strcpy(ss,s);//复制字符串,不改变原字符串的大小写strupr(ss);//将字符串ss转换为大写形式p=ss;while(*p!='\0')sum+=*p++;printf("\nsum====================%d",sum);return sum;}int Hash1(NA str){//哈希函数int m;n=fold(str);//先将用户名进行折叠处理m=n%HASHSIZE; //折叠处理后的数,用除留余数法构造哈希函数return m; //并返回模值}int Hash2(NA str){//哈希函数long n;int m;n = atoi(str);//把字符串转换成整型数.m=n%HAreturn m; //并返回模值}Status collision(int p,int &c){//冲突处理函数,采用二次探测再散列法解决冲突int i,q;i=c/2+1;while(i<HASHSIZE){if(c%2==0){c++;q=(p+i*i)%HASHSIZE;if(q>=0) return q;else i=c/2+1;}else{q=(p-i*i)%HASHSIZE;c++;if(q>=0) return q;else i=c/2+1;}}return UNSUCCESS;}void benGetTime();void CreateHash1(HashTable* H,Record* a){//建表,以人的姓名为关键字,建立相应的散列表//若哈希地址冲突,进行冲突处理benGetTime();int i,p=-1,c,pp;for(i=0;i<NUM_BER;i++){c=0;p=Hash1(a[i].name);pp=p;while(H->elem[pp]!=NULL) {pp=collision(p,c);if(pp<0){printf("第%d记录无法解决冲突",i+1);//需要显示冲突次数时输出continue;}//无法解决冲突,跳入下一循环}H->elem[pp]=&(a[i]); //求得哈希地址,将信息存入H->count++;printf("第%d个记录冲突次数为%d。
数据结构课程设计----线性开型寻址散列查找、插入、删除
山东大学软件学院数据结构课程设计报告设计题目:线性开型寻址散列查找、插入、删除学号—姓名___________年级___________专业______班级__________学期11-12学年第二学期日期:2012年月曰一、需求描述1.1散列表的研究意义:一般的线性表、树中,记录在结构中的相对位置是随机的即和记录的关键字之间不存在确定的关系,在结构中查找记录时需进行一系列和关键字的比较。
这一类查找方法建立在“比较”的基础上,查找的效率与比较次数密切相关。
理想的情况是能直接找到需要的记录,因此必须在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。
因而查找时,只需根据这个对应关系f找到给定值K的像f(K)。
若结构中存在关键字和K相等的记录,则必定在f(K)的存储位置上,由此不需要进行比较便可直接取得所查记录。
在此,称这个对应关系f为哈希函数,按这个思想建立的表为散列表(哈希表)。
1.2散列表的定义散列(Hash ):根据记录的关键字的值来确定其存储地址。
建立散列表,要在记录的存储地址和它的关键字之间建立一个确定的对应关系。
散列函数(Hash function ):在记录的关键字和记录的存储地址之间建立的一种对应关系。
散列函数是一种映像,是从关键字空间到存储地址空间的映像,可表示为Add (ai)=H(keyi)其中:ai是表中的一个记录,add(ai) 是ai的存储地址,keyi是ai的关键字。
冲突(collisio n) :不同的关键字经过散列函数计算后得到相同的地址,也就是说key1工key2,但是H(key1)=H(key2) 的现象叫做冲突。
具有相同函数值的几个关键字就称为该散列函数的同义词。
一般情况下,冲突只能减少,并不可避免。
当冲突发生时,就要设定一种处理冲突的办法。
散列表(Hash table ):应用散列函数和处理冲突的办法将一组关键字映像到一个有限的地址集上,并以关键字在地址集上的像作为记录在地址中的存储地址。
散列表实验报告
课程名称:数据结构实验项目:散列表题目:散列表实验一、需求分析1、实验目标掌握散列表的构造方法以及冲突处理方法,实现散列表的运算算法。
2、程序的输入和输出输入:void insertRec(char x[], char y[])输出:void print() {const char space[] = " ";int i, k;for (i = 0; i < N; i++) {k = H(a[i].key);cout << i << ":\t"<< a[i].key << "\t"<< a[i].value << "\t";if (strlen(a[i].key) > 0)cout << "(" << k << ")";cout << endl;}二、概要设计1、数据结构带头节点的线性链表。
主要的操作:查找节点,插入节点,更新节点,打印链表。
2、程序的模块分为两个程序文件。
主要模块如下:void init();void insertRec(char x[], char y[]);int searchRec(char x[]);int deleteRec(char x[]);void print();三、详细设计1、数据结构#include <cstdlib>#include <iostream>using namespace std;const int N = 17; //散列表长struct record { //记录char key[24];char value[24];int deleted;};record a[N]; //散列表int H(char key[]); //散列函数void init();void insertRec(char x[], char y[]);int searchRec(char x[]);int deleteRec(char x[]);void print();int main(int argc, char *argv[]){int i, k;char x[24], y[24];init();cout << "输入要插入的记录: \n";for (i = 0; i < 14; i++) {cin >> x >> y;insertRec(x, y);print();}system("PAUSE");return EXIT_SUCCESS;}void insertRec(char x[], char y[]) { int i, k;i = H(x);while (strlen(a[i].key) > 0) {i++; //线性探测if (i == N) i = 0; //绕回表头}strcpy(a[i].key, x);strcpy(a[i].value, y);}int deleteRec(char x[]) {}int searchRec(char x[]) {}int H(char key[]) {int i = key[0], j = key[1];return (i*i + j*j) % N;}void print() {const char space[] = " "; int i, k;for (i = 0; i < N; i++) {k = H(a[i].key);cout << i << ":\t"<< a[i].key << "\t"<< a[i].value << "\t";if (strlen(a[i].key) > 0)cout << "(" << k << ")"; cout << endl;}}void init() {int i;for (i = 0; i < N; i++) {strcpy(a[i].key, "");strcpy(a[i].value, "");a[i].deleted = 0;}}四、测试结果1、输入autumn 秋天2、输出0:1:2:3:4:5:6:7:8:9:10:11:12:autumn秋天<12>13:14:15:16:。
《散列表的设计与实现》课程设计说明书
届课程设计《散列表的设计与实现》设计说明书学生姓名学号所属学院信息工程学院专业计算机科学与技术班级计算机指导教师教师职称讲师塔里木大学教务处制目录前言 (1)1.1设计背景和意义 (1)1.1.1数据结构简介 (1)1.1.2选择算法的原因 (1)1.2设计的原理和内容 (1)正文 (1)2.1 设计的目的和意义 (1)2.2 目标和总体方案 (2)2.3 设计方法和内容 (2)2.3.1 硬件环境 (2)2.3.2软件环境 (2)2.3.3设计内容 (3)2.3.4 设计流程图 (3)2.4 设计创新与关键技术 (6)2.5结论 (6)2.5.1存在的问题 (6)2.5.2解决方案 (7)参考文献 (10)程序的设计思想和内容............................. 错误!未定义书签。
3.1程序设计的初始运行环境 .................... 错误!未定义书签。
3.2散列表的初始化............................ 错误!未定义书签。
3.3数据的插入................................ 错误!未定义书签。
3.4数据元素的查找............................ 错误!未定义书签。
3.5数据的删除................................ 错误!未定义书签。
3.6数据的合并................................ 错误!未定义书签。
3.7完成...................................... 错误!未定义书签。
前言1.1设计背景和意义1.1.1数据结构简介数据结构是计算机程序设计的重要理论设计基础,是一门综合性的专业基础科。
数据结构是研究数据之间的相互关系,也即数据的组织形式的一门科学。
它不仅是计算机学科的核心课程,数据结构是计算机存储、组织数据的方式。
数据结构实验报告(C语言)顺序表__排序
int i,j,n,x,change; n=L->length; change=1; for(i=1;i<=n-1 && change;++i){
change=0; for(j=1;j<=n-i-1;++j)
if(L->r[j] > L->r[j+1]){ x=L->r[j]; L->r[j]=L->r[j+1]; L->r[j+1]=x; change=1;
void QuickSort(SqeList *L,int low,int high){ int mid; if(low<high){ mid=Partition(L,low,high); QuickSort(L,low,mid-1); QuickSort(L,mid+1,high); }
}
//直接选择排序
printf("\n7-直接选择排序结果为:\n"); SelectSort(&l); PrintList(&l); printf("\n"); printf("\n8-二路归并结果为:\n"); MergeSort(&l);
PrintList(&l); printf("\n"); } else printf("请输入大于 0 的值: "); return 0; }
} else{
MR->r[k]=R->r[j]; ++j; } ++k; } while(i<=mid) MR->r[k++]=R->r[i++]; while(j<=high) MR->r[k++]=R->r[j++]; }
严蔚敏《数据结构》(C语言版)配套题库(章节题库1-6章)【圣才出品】
2.计算机算法指的是解决问题的步骤序列,它必须具备( )三个特性。 A.可执行性、可移植性、可扩充性 B.可执行性、确定性、有穷性 C.确定性、有穷性、稳定性 D.易读性、稳定性、安全性 【答案】B 【解析】计算机算法是以一步接一步的方式来详细描述计算机如何将输入转化为所要求 的输出的过程,或者说,算法是对计算机上执行的计算过程的具体描述,也就是解决问题的 步骤序列。一个算法通常需要具备五大特性:有穷性;确定性;可执行性;输入一个算法有 零个或多个输入;输出一个算法有零个或者多个输出。
FOR i:=n-1 DOWNT0 1 DO FOR j:=l TO i DO IF A[ j]>A[ j+1] THEN A[ j]与 A[ j+1]对换;
其中 n 为正整数,则最后一行的语句最坏情况下的时间复杂度是( )。 A.D(n) B.O(nlogn) C.O(n3) D.O(n2) 【答案】D 【解析】这个是冒泡排序,最坏的情况下需要进行 1+2+...+n-1 次交换,即时间复杂 度是 O(n2)。
6.数据结构的抽象操作的定义与具体实现有关。( ) 【答案】× 【解析】数据结构的抽象操作定义取决于客观存在的一组逻辑特性,与其在计算机内具 体表示和实现无关。
7.顺序存储方式的优点是存储密度大,且插入、删除运算效率高。( ) 【答案】× 【解析】前者正确,后者错误。顺序存储方式在插入、删除元素时需要挪动大量的元素, 执行效率较低。
3.以下说法错误的是( )。 (1)算法原地工作的含义是指不需要任何额外的辅助空间 (2)在相同的规模 n 下,复杂度 O(n)的算法在时间上总是优于复杂度 O(2n)的 算法
散列表的基本结构
散列表的基本结构散列表是一种常见的数据结构,也被称为哈希表或者哈希映射。
它是一种基于数组的数据结构,用于存储键值对。
散列表使用哈希函数将键映射到数组中的位置。
这使得查找、插入和删除操作的时间复杂度为常数级别(O(1))。
在本文中,我们将详细介绍散列表的基本结构和实现。
1. 散列表的基本结构散列表由两个基本部分组成:散列函数和数组。
散列函数将键映射到数组中的位置。
数组用于存储键值对。
下面是一个简单的散列表示例:```class HashTable:def __init__(self):self.size = 10self.table = [None] * self.sizedef hash(self, key):return key % self.sizedef insert(self, key, value):index = self.hash(key)self.table[index] = valuedef search(self, key):index = self.hash(key)return self.table[index]def delete(self, key):index = self.hash(key)self.table[index] = None```在上面的示例中,我们使用一个数组来存储键值对。
数组的大小为10,这意味着我们使用10个桶来存储数据。
每个桶都可以存储一个键值对。
我们使用散列函数将键映射到数组中的位置。
这个散列函数非常简单,它只是将键模10,然后返回余数。
这意味着键的范围可以是0到9。
我们还定义了四个基本操作:插入、查找、删除和散列函数。
插入操作将一个键值对存储在数组中的正确位置。
查找操作使用散列函数来查找一个键值对。
删除操作将一个键值对从数组中删除。
散列函数将键映射到数组中的位置。
2. 散列函数的选择散列函数的选择非常重要,因为它直接影响到散列表的性能。
一个好的散列函数应该满足以下要求:- 易于计算:散列函数应该是快速计算的,这样可以快速地将键映射到数组中的位置。
数据结构实验报告队列的表示与实现
一旦visit失败, 则操作失败。
链队列:
//单链队列-—队列的链式存储结构
typedef struct QNode{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct{
if(! Q.front )exit(OVERFLOW); //存储分配失败
Q.front —〉next =NULL;
return OK;}
Status DestoryQueue(LinkQueue &Q){//销毁队列Q, Q不再存在
while(Q.front){
Q。rear=Q.front —〉next;
DestoryQueue(&Q)//初始条件:队列Q已存在
//操作结果: 队列Q被销毁, 不再存在
ClearQueue(&Q)//初始条件:队列Q已存在
//操作结果: 将Q清为空队列
QueueEmpty(Q)//初始条件: 队列Q已存在
//操作结果:若队列Q为空队列, 则返回TRUE, 否则FALSE
QueuePtr front;//队头指针
QueuePtr rear;//队尾指针
}LinkQueue;
//—---—单链队列的基本操作的算法描述—-————
status INitQueue(LinkQueue &Q){//构造一个空队列Q
Q.front=Q。rear=(QueuePtr)malloc(sizeof(QNode));
数据结构实验报告
姓名
学号
号
实验地点
数学楼
最新数据结构(C语言版)第三版__清华大学出版社_习题参考答案
只要有信心,努力,一切可以改变。
附录习题参考答案习题1参考答案1.1.选择题(1). A. (2). A. (3). A. (4). B.C. (5). A. (6). A. (7). C. (8). A. (9). B. (10.) A.1.2.填空题(1). 数据关系(2). 逻辑结构物理结构(3). 线性数据结构树型结构图结构(4). 顺序存储链式存储索引存储散列表(Hash)存储(5). 变量的取值范围操作的类别(6). 数据元素间的逻辑关系数据元素存储方式或者数据元素的物理关系(7). 关系网状结构树结构(8). 空间复杂度和时间复杂度(9). 空间时间(10). Ο(n)1.3 名词解释如下:数据:数据是信息的载体是计算机程序加工和处理的对象包括数值数据和非数值数据数据项:数据项指不可分割的、具有独立意义的最小数据单位数据项有时也称为字段或域数据元素:数据元素是数据的基本单位在计算机程序中通常作为一个整体进行考虑和处理一个数据元素可由若干个数据项组成数据逻辑结构:数据的逻辑结构就是指数据元素间的关系数据存储结构:数据的物理结构表示数据元素的存储方式或者数据元素的物理关系数据类型:是指变量的取值范围和所能够进行的操作的总和算法:是对特定问题求解步骤的一种描述是指令的有限序列1.4 语句的时间复杂度为:(1) Ο(n2)(2) Ο(n2)(3) Ο(n2)(4) Ο(n-1)(5) Ο(n3)1.5 参考程序:main(){int XYZ;scanf("%d %d%d"&X&YZ);if (X>=Y)if(X>=Z)if (Y>=Z) { printf("%d %d%d"XYZ);}else{ printf("%d %d%d"XZY);}else{ printf("%d %d%d"ZXY);}else if(Z>=X)if (Y>=Z) { printf("%d %d%d"YZX);}else{ printf("%d%d%d"ZYX);}else{ printf("%d%d%d"YXZ);}}1.6 参考程序:main(){int in;float xa[]p;printf("\nn=");scanf("%f"&n);printf("\nx=");scanf("%f"&x);for(i=0;i<=n;i++)scanf("%f "&a[i]);p=a[0];for(i=1;i<=n;i++){ p=p+a[i]*x;x=x*x;}printf("%f"p)'}习题2参考答案2.1选择题(1). C. (2). B. (3). B. (4). B. 5. D. 6. B. 7. B. 8. A. 9. A. 10. D.2.2.填空题(1). 有限序列(2). 顺序存储和链式存储(3). O(n) O(n)(4). n-i+1 n-i(5). 链式(6). 数据指针(7). 前驱后继(8). Ο(1) Ο(n)(9). s->next=p->next; p->next=s ;(10). s->next2.3. 解题思路:将顺序表A中的元素输入数组a若数组a中元素个数为n将下标为012...(n-1)/2的元素依次与下标为nn-1...(n-1)/2的元素交换输出数组a的元素参考程序如下:main(){int in;float ta[];printf("\nn=");scanf("%f"&n);for(i=0;i<=n-1;i++)scanf("%f "&a[i]);for(i=0;i<=(n-1)/2;i++){ t=a[i]; a[i] =a[n-1-i]; a[n-1-i]=t;} for(i=0;i<=n-1;i++)printf("%f"a[i]);}2.4 算法与程序:main(){int in;float ta[];printf("\nn=");scanf("%f"&n);for(i=0;i<n;i++)scanf("%f "&a[i]);for(i=1;i<n;i++)if(a[i]>a[0]{ t=a[i]; a[i] =a[0]; a[0]=t;}printf("%f"a[0]);for(i=2;i<n;i++)if(a[i]>a[1]{ t=a[i]; a[i] =a[1]; a[1]=t;}printf("%f"a[0]);}2.5 算法与程序:main(){int ijkn;float xta[];printf("\nx=");scanf("%f"&x);printf("\nn=");scanf("%f"&n);for(i=0;i<n;i++)scanf("%f "&a[i]); // 输入线性表中的元素for (i=0; i<n; i++) { // 对线性表中的元素递增排序k=i;for (j=i+1; j<n; j++) if (a[j]<a[k]) k=j; if (k<>j) {t=a[i];a[i]=a[k];a[k]=t;}}for(i=0;i<n;i++) // 在线性表中找到合适的位置if(a[i]>x) break;for(k=n-1;k>=i;i--) // 移动线性表中元素然后插入元素xa[k+1]=a[k];a[i]=x;for(i=0;i<=n;i++) // 依次输出线性表中的元素printf("%f"a[i]);}2.6 算法思路:依次扫描A和B的元素比较A、B当前的元素的值将较小值的元素赋给C如此直到一个线性表扫描完毕最后将未扫描完顺序表中的余下部分赋给C即可C的容量要能够容纳A、B两个线性表相加的长度有序表的合并算法:void merge (SeqList ASeqList BSeqList *C){ int ijk;i=0;j=0;k=0;while ( i<=st && j<=st )if (A.data[i]<=B.data[j])C->data[k++]=A.data[i++];elseC->data[k++]=B.data[j++];while (i<=st )C->data[k++]= A.data[i++];while (j<=st )C->data[k++]=B.data[j++];C->last=k-1;}2.7 算法思路:依次将A中的元素和B的元素比较将值相等的元素赋给C如此直到线性表扫描完毕线性表C就是所求递增有序线性表算法:void merge (SeqList ASeqList BSeqList *C){ int ijk;i=0;j=0;k=0;while ( i<=st)while(j<=st )if (A.data[i]=B.data[j])C->data[k++]=A.data[i++];C->last=k-1;}习题3参考答案3.1.选择题(1). D (2). C (3). D (4). C (5). B (6). C (7). C (8). C (9). B (10).AB (11). D (12). B (13). D (14). C (15). C (16). D(17). D (18). C (19). C (20). C 3.2.填空题(1) FILOFIFO(2) -13 4 X * + 2 Y * 3 / -(3) stack.topstack.s[stack.top]=x(4) p>llink->rlink=p->rlinkp->rlink->llink=p->rlink(5) (R-F+M)%M(6) top1+1=top2(7) F==R(8) front==rear(9) front==(rear+1)%n(10) N-13.3 答:一般线性表使用数组来表示的线性表一般有插入、删除、读取等对于任意元素的操作而栈只是一种特殊的线性表栈只能在线性表的一端插入(称为入栈push)或者读取栈顶元素或者称为"弹出、出栈"(pop)3.4 答:相同点:栈和队列都是特殊的线性表只在端点处进行插入删除操作不同点:栈只在一端(栈顶)进行插入删除操作;队列在一端(top)删除一端(rear)插入3.5 答:可能序列有14种:ABCD; ACBD; ACDB; ABDC; ADCB; BACD; BADC; BCAD; BCDA; BDCA; CBAD; CBDA; CDBA; DCBA3.6 答:不能得到435612最先出栈的是4则按321的方式出不可能得到1在2前的序列可以得到135426按如下方式进行push(1)pop()push(2)push(3)pop()push(4)push(5)pop()pop()pop()push(6)pop()3.7 答:stack3.8 非递归:int vonvert (int noint a[]) //将十进制数转换为2进制存放在a[] 并返回位数{int r;SeStack s*p;P=&s;Init_stack(p);while(no){push(pno%2);no/=10;}r=0;while(!empty_stack(p)){pop(pa+r);r++;}return r;}递归算法:void convert(int no){if(no/2>0){Convert(no/2);Printf("%d"no%2);}elseprintf("%d"no);}3.9 参考程序:void view(SeStack s){SeStack *p; //假设栈元素为字符型char c;p=&s;while(!empty_stack(p)){c=pop(p);printf("%c"c);}printf("\n");}3.10 答:char3.11 参考程序:void out(linkqueue q){int e;while(q.rear !=q.front ){dequeue(qe);print(e); //打印}}习题4参考答案4.1 选择题:(1). A (2). D (3). C (4). C (5). B (6). B (7). D (8). A (9). B (10). D 4.2 填空题:(1)串长相等且对应位置字符相等(2)不含任何元素的串(3)所含字符均是空格所含空格数(4) 10(5) "hello boy"(6) 13(7) 1066(8)模式匹配(9)串中所含不同字符的个数(10) 364.3 StrLength (s)=14StrLength (t)=4SubStr( s87)=" STUDENT"SubStr(t21)="O"StrIndex(s"A")=3StrIndex (st)=0StrRep(s"STUDENT"q)=" I AM A WORKER"4.4 StrRep(s"Y""+");StrRep(s"+*""*Y");4.5 空串:不含任何字符;空格串:所含字符都是空格串变量和串常量:串常量在程序的执行过程中只能引用不能改变;串变量的值在程序执行过程中是可以改变和重新赋值的主串与子串:子串是主串的一个子集串变量的名字与串变量的值:串变量的名字表示串值的标识符4.6int EQUAl(ST){char *p*q;p=&S;q=&T;while(*p&&*q){if(*p!=*q)return *p-*q;p++;q++;}return *p-*q;}4.7(1)6*8*6=288(2)1000+47*6=1282(3)1000+(8+4)*8=1096(4)1000+(6*7+4)*8=13684.8习题5参考答案5.1 选择(1)C(2)B(3)C(4)B(5)C(6)D(7)C(8)C(9)B(10)C (11)B(12)C(13)C(14)C(15)C(16)B5.2 填空(1)1(2)1036;1040(3)2i(4) 1 ; n ; n-1 ; 2(5)2k-1;2k-1(6)ACDBGJKIHFE(7)p!=NULL(8)Huffman树(9)其第一个孩子; 下一个兄弟(10)先序遍历;中序遍历5.3叶子结点:C、F、G、L、I、M、K;非终端结点:A、B、D、E、J;各结点的度:结点: A B C D E F G L I J K M度: 4 3 0 1 2 0 0 0 0 1 0 0树深:4无序树形态如下:二叉树形态如下:5.5二叉链表如下:三叉链表如下:5.6先序遍历序列:ABDEHICFJG中序遍历序列:DBHEIAFJCG后序遍历序列:DHIEBJFGCA5.7(1) 先序序列和中序序列相同:空树或缺左子树的单支树;(2) 后序序列和中序序列相同:空树或缺右子树的单支树;(3) 先序序列和后序序列相同:空树或只有根结点的二叉树5.8这棵二叉树为:先根遍历序列:ABFGLCDIEJMK后根遍历序列:FGLBCIDMJKEA层次遍历序列:ABCDEFGLIJKM5.10证明:设树中结点总数为n叶子结点数为n0则n=n0 + n1 + ...... + nm (1)再设树中分支数目为B则B=n1 + 2n2 + 3n3 + ...... + m nm (2)因为除根结点外每个结点均对应一个进入它的分支所以有n= B + 1 (3)将(1)和(2)代入(3)得n0 + n1 + ...... + nm = n1 + 2n2 + 3n3 + ...... + m nm + 1 从而可得叶子结点数为:n0 = n2 + 2n3 + ...... + (m-1)nm + 15.11由5.10结论得n0 = (k-1)nk + 1又由 n=n0 + nk得nk= n-n0代入上式得n0 = (k-1)(n-n0)+ 1叶子结点数为:n0 = n (k-1) / k5.12int NodeCount(BiTree T){ //计算结点总数if(T)if (T-> lchild==NULL )&&( T --> rchild==NULL )return 1;elsereturn NodeCount(T-> lchild ) +Node ( T --> rchild )+1; elsereturn 0;}void ExchangeLR(Bitree bt){/* 将bt所指二叉树中所有结点的左、右子树相互交换 */ if (bt && (bt->lchild || bt->rchild)) {bt->lchild<->bt->rchild;Exchange-lr(bt->lchild);Exchange-lr(bt->rchild);}}/* ExchangeLR */5.14int IsFullBitree(Bitree T){/* 是则返回1否则返回0*/Init_Queue(Q); /* 初始化队列*/flag=0;In_Queue(QT); /* 根指针入队列按层次遍历*/while(!Empty_Queue (Q)){Out_Queue(Qp);if(!p) flag=1; /* 若本次出队列的是空指针时则修改flag值为1若以后出队列的指针存在非空则可断定不是完全二叉树 */else if (flag) return 0; /*断定不是完全二叉树 */ else{In_Queue(Qp->lchild);In_Queue(Qp->rchild); /* 不管孩子是否为空都入队列*/}}/* while */return 1; /* 只有从某个孩子指针开始之后所有孩子指针都为空才可断定为完全二叉树*/}/* IsFullBitree */转换的二叉树为:5.16对应的森林分别为:5.17typedef char elemtype;typedef struct{ elemtype data;int parent;} NodeType;(1) 求树中结点双亲的算法:int Parent(NodeType t[ ]elemtype x){/* x不存在时返回-2否则返回x双亲的下标(根的双亲为-1 */for(i=0;i<MAXNODE;i++)if(x==t[i].data) return t[i].parent; return -2;}/*Parent*/(2) 求树中结点孩子的算法:void Children(NodeType t[ ]elemtype x){for(i=0;i<MAXNODE;i++){if(x==t[i].data)break;/*找到x退出循环*/}/*for*/if(i>=MAXNODE) printf("x不存在\n"); else {flag=0;for(j=0;j<MAXNODE;j++)if(i==t[j].parent){ printf("x的孩子:%c\n"t[j].data);flag=1;}if(flag==0) printf("x无孩子\n");}/*Children*/5.18typedef char elemtype;typedef struct ChildNode{ int childcode;struct ChildNode *nextchild;}typedef struct{ elemtype data;struct ChildNode *firstchild;} NodeType;(1) 求树中结点双亲的算法:int ParentCL(NodeType t[ ]elemtype x){/* x不存在时返回-2否则返回x双亲的下标 */for(i=0;i<MAXNODE;i++)if(x==t[i].data) {loc=i;/*记下x的下标*/break;}if(i>=MAXNODE) return -2; /* x不存在 *//*搜索x的双亲*/for(i=0;i<MAXNODE;i++)for(p=t[i].firstchild;p!=NULL;p=p->nextchild) if(loc==p->childcode)return i; /*返回x结点的双亲下标*/}/* ParentL */(2) 求树中结点孩子的算法:void ChildrenCL(NodeType t[ ]elemtype x){for(i=0;i<MAXNODE;i++)if(x==t[i].data) /*依次打印x的孩子*/{flag=0; /* x存在 */for(p=t[i].firstchild;p;p=p->nextchild){ printf("x的孩子:%c\n"t[p-> childcode].data);flag=1;}if(flag==0) printf("x无孩子\n");return;}/*if*/printf("x不存在\n");return;}/* ChildrenL */5.19typedef char elemtype;typedef struct TreeNode{ elemtype data;struct TreeNode *firstchild; struct TreeNode *nextsibling; } NodeType;void ChildrenCSL(NodeType *telemtype x){ /* 层次遍历方法 */Init_Queue(Q); /* 初始化队列 */In_Queue(Qt);count=0;while(!Empty_Queue (Q)){Out_Queue(Qp);if(p->data==x){ /*输出x的孩子*/p=p->firstchild;if(!p) printf("无孩子\n");else{ printf("x的第%i个孩子:%c\n"++countp->data);/*输出第一个孩子*/p=p->nextsibling; /*沿右分支*/while(p){printf("x的第%i个孩子:%c\n"++countp->data);p=p-> nextsibling;}}return;}if(p-> firstchild) In_Queue(Qp-> firstchild);if(p-> nextsibling) In_Queue(Qp-> nextsibling);}}/* ChildrenCSL */5.20(1) 哈夫曼树为:(2) 在上述哈夫曼树的每个左分支上标以1右分支上标以0并设这7个字母分别为A、B、C、D、E、F和H如下图所示:则它们的哈夫曼树为分别为:A:1100B:1101C:10D:011E:00F:010H:111习题6参考答案6.1 选择题(1)C (2)A (3)B(4)C(5)B______条边(6)B(7)A(8)A(9)B(10)A(11)A(12)A(13)B(14)A(15)B(16)A(17)C 6.2 填空(1) 4(2) 1对多 ; 多对多(3) n-1 ; n(4) 0_(5)有向图(6) 1(7)一半(8)一半(9)___第i个链表中边表结点数___(10)___第i个链表中边表结点数___(11)深度优先遍历;广度优先遍历(12)O(n2)(13)___无回路6.3(1)邻接矩阵:(2)邻接链表:(3)每个顶点的度:顶点度V1 3V2 3V3 2V4 3V5 36.4(1)邻接链表:(2)逆邻接链表:(3)顶点入度出度V1 3 0V2 2 2V3 1 2V4 1 3V5 2 1V6 2 36.5(1)深度优先查找遍历序列:V1 V2 V3 V4 V5; V1 V3 V5 V4 V2; V1 V4 V3 V5 V2 (1)广度优先查找遍历序列:V1 V2 V3 V4 V5; V1 V3 V2 V4 V5; V1 V4 V3 V2 V56.6有两个连通分量:6.7顶点(1)(2)(3)(4)(5)Low Close Cost VexLow CloseCost VexLow CloseCost VexLow CloseCost VexLow CloseCost VexV10 00 00 00 00 0V21 00 00 00 00 0V31 01 00 00 00 0V43 02 12 10 10 1V5∞ 05 13 22 30 3U{v1} {v1v2} {v1v2v3} {v1 v2 v3 v4} {v1 v2 v3 v4 v5} T {} { (v1 v2) } {(v1 v2) (v1 v3) } {(v1 v2) (v1 v3) (v2 v4) } {(v1 v2) (v1v3)(v2v4)(v4v5) }最小生成树的示意图如下:6.8拓扑排序结果: V3--> V1 --> V4 --> V5 --> V2 --> V66.9(1)建立无向图邻接矩阵算法:提示:参见算法6.1因为无向图的邻接矩阵是对称的所以有for (k=0; k<G ->e; k++) /*输入e条边建立无向图邻接矩阵*/{ scanf("\n%d%d"&i&j);G ->edges[i][j]= G ->edges[j][i]=1;}(2)建立无向网邻接矩阵算法:提示:参见算法6.1初始化邻接矩阵:#define INFINITY 32768 /* 表示极大值*/for(i=0;i<G->n;i++)for(j=0;j<G->n;j++) G->edges[i][j]= INFINITY;输入边的信息:不仅要输入边邻接的两个顶点序号还要输入边上的权值for (k=0; k<G ->e; k++) /*输入e条边建立无向网邻接矩阵*/{ scanf("\n%d%d%d"&i&j&cost); /*设权值为int型*/G ->edges[i][j]= G ->edges[j][i]=cost;/*对称矩阵*/}(3)建立有向图邻接矩阵算法:提示:参见算法6.16.10(1)建立无向图邻接链表算法:typedef VertexType char;int Create_NgAdjList(ALGraph *G){ /* 输入无向图的顶点数、边数、顶点信息和边的信息建立邻接表 */scanf("%d"&n); if(n<0) return -1; /* 顶点数不能为负 */G->n=n;scanf("%d"&e); if(e<0) return =1; /*边数不能为负 */G->e=e;for(m=0;m< G->n ;m++)G-> adjlist [m].firstedge=NULL; /*置每个单链表为空表*/for(m=0;m< G->n;m++)G->adjlist[m].vertex=getchar(); /*输入各顶点的符号*/for(m=1;m<= G->e; m++){scanf("\n%d%d"&i&j); /* 输入一对邻接顶点序号*/if((i<0 || j<0) return -1;p=(EdgeNode*)malloc(sizeof(EdgeNode));/*在第i+1个链表中插入一个边表结点*/ p->adjvex=j;p->next= G-> adjlist [i].firstedge;G-> adjlist [i].firstedge=p;p=(EdgeNode*)malloc(sizeof(EdgeNode));/*在第j+1个链表中插入一个边表结点*/ p->adjvex=i;p->next= G-> adjlist [j].firstedge;G-> adjlist [j].firstedge=p;} /* for*/return 0; /*成功*/}//Create_NgAdjList(2)建立有向图逆邻接链表算法:typedef VertexType char;int Create_AdjList(ALGraph *G){ /* 输入有向图的顶点数、边数、顶点信息和边的信息建立逆邻接链表 */scanf("%d"&n); if(n<0) return -1; /* 顶点数不能为负 */G->n=n;scanf("%d"&e); if(e<0) return =1; /*弧数不能为负 */G->e=e;for(m=0;m< G->n; m++)G-> adjlist [m].firstedge=NULL; /*置每个单链表为空表*/for(m=0;m< G->n;m++)G->adjlist[m].vertex=getchar(); /*输入各顶点的符号*/for(m=1;m<= G->e ; m++){scanf("\n%d%d"&t&h); /* 输入弧尾和弧头序号*/if((t<0 || h<0) return -1;p=(EdgeNode*)malloc(sizeof(EdgeNode));/*在第h+1个链表中插入一个边表结点*/ p->adjvex=t;p->next= G-> adjlist [h].firstedge;G-> adjlist [h].firstedge=p;} /* for*/return 0; /*成功*/}//Create_AdjList6.11void Create_AdjM(ALGraph *G1MGraph *G2){ /*通过无向图的邻接链表G1生成无向图的邻接矩阵G2*/G2->n=G1->n; G2->e=G1->e;for(i=0;i<G2->n;i++) /* 置G2每个元素为0 */for(j=0;j<G2->n;j++) G2->edges[i][j]= 0;for(m=0;m< G1->n;m++)G2->vexs[m]=G1->adjlist[m].vertex; /*复制顶点信息*/num=(G1->n/2==0?G1->n/2:G1->n/2+1); /*只要搜索前n/2个单链表即可*/for(m=0;m< num;m++){ p=G1->adjlist[m].firstedge;while(p){ /* 无向图的存储具有对称性*/G2->edges[m][ p->adjvex ]= G2->edges[p->adjvex ] [m] =1;p==p->next;}}/* for */}/*Create_AdjM */void Create_AdjL(ALGraph *G1MGraph *G2){ /*通过无向图的邻接矩阵G1生成无向图的邻接链表G2*/G2->n=G1->n; G2->e=G1->e;for(i=0;i<G1->n;i++) /* 建立每个单链表 */{ G2->vexs[i]=G1->adjlist[i].vertex;G2->adjlist[i].firstedge=NULL;for(j=i; j<G1->n; j++) /*对称矩阵只要搜索主对角以上的元素即可*/{ if(G1->edges[i][j]== 1){ p=(EdgeNode*)malloc(sizeof(EdgeNode));/*在第i+1个链表中插入一个边表结点*/p->adjvex=j;p->next= G-> adjlist [i].firstedge;G-> adjlist [i].firstedge=p;p=(EdgeNode*)malloc(sizeof(EdgeNode));/*在第j+1个链表中插入一个边表结点*/p->adjvex=i;p->next= G-> adjlist [j].firstedge;G-> adjlist [j].firstedge=p;}/*if*/}/* for*/}/* for*/}/* Create_AdjL */6.13(1) 邻接矩阵中1的个数的一半;(2) 若位于[i-1j-1]或[j-1i-1]位置的元素值等于1则有边相连否则没有(3) 顶点i的度等于第i-1行中或第i-1列中1的个数6.14(1) 邻接链表中边表结点的个数的一半;(2) 若第i-1(或j-1)个单链表中存在adjvex域值等于j-1(或i-1)的边表结点则有边相连否则没有(3) 顶点i的度等于第i-1个单链表中边表结点的个数提示:参见算法6.2 和6.3习题 7参考答案7.1 选择题(1)C (2)C (3) C (4)B (5) A (6)A (7) D (8)B (9)D (10) B(11)B (12)A (13)C (14)C (15)A (16)D (17)C (18)BC (19)B (20)A7.2 填空题(1) O(n)O(log2n)(2) 12485log2(n+1)-1(3)小于大于(4)增序序列(5)m-1(6) 70; 342055(7) n/m(8)开放地址法链地址法(9)产生冲突的可能性就越大产生冲突的可能性就越小(10)关键码直接(11)②①⑦(12) 1616821(13)直接定址法数字分析法平方取中法折叠法除留余数法随机数法(14)开放地址法再哈希法链地址法建立一个公共溢出区(15)装满程度(16)索引快(17)哈希函数装填因子(18)一个结点(19)中序(20)等于7.3 一棵二叉排序树(又称二叉查找树)或者是一棵空树或者是一棵同时满足下列条件的二叉树:(1)若它的左子树不空则左子树上所有结点的键值均小于它根结点键值(2)若它的右子树不空则右子树上所有结点的键值均大于它根结点键值(3)它的左、右子树也分别为二叉排序树7.4 对地址单元d=H(K)如发生冲突以d为中心在左右两边交替进行探测按照二次探测法键值K的散列地址序列为:do=H(K)d1=(d0+12)mod md2=(d0-12)mod md3=(d0+22)mod md4=(d0-12)mod m......7.5 衡量算法的标准有很多时间复杂度只是其中之一尽管有些算法时间性能很好但是其他方面可能就存在着不足比如散列查找的时间性能很优越但是需要关注如何合理地构造散列函数问题而且总存在着冲突等现象为了解决冲突还得采用其他方法二分查找也是有代价的因为事先必须对整个查找区间进行排序而排序也是费时的所以常应用于频繁查找的场合对于顺序查找尽管效率不高但却比较简单常用于查找范围较小或偶而进行查找的情况7.6此法要求设立多个散列函数Hii=1...k当给定值K与闭散列表中的某个键值是相对于某个散列函数Hi的同义词因而发生冲突时继续计算该给定值K在下一个散列函数Hi+1下的散列地址直到不再产生冲突为止7.7散列表由两个一维数组组成一个称为基本表另一个称为溢出表插入首先在基本表上进行;假如发生冲突则将同义词存人溢出表7.8 结点个数为n时高度最小的树的高度为1有两层它有n-1个叶结点1个分支结点;高度最大的树的高度为n-l有n层它有1个叶结点n-1个分支结点7.9 设顺序查找以h为表头指针的有序链表若查找成功则返回结点指针p查找失败则返回null值pointer sqesrearch(pointer hint xpointerp){p=null;while(h)if(x>h->key)h=h->link;else{if(x==h->key)p=h;return(p);}}虽然链表中的结点是按从小到大的顺序排列的但是其存储结构为单链表查找结点时只能从头指针开始逐步进行搜索故不能用折半(二分)查找7.10 分析:对二叉排序树来讲其中根遍历序列为一个递增有序序列因此对给定的二叉树进行中根遍历如果始终能保证前一个值比后一个值小则说明该二叉树是二叉排序树int bsbtr (bitreptr T) /*predt记录当前结点前趋值初值为-∞*/{ if (T==NULL) return(1);else{b1=bsbtr(T->lchild);/*判断左子树*/if (!b1|| (predt>=T->data)) return(0);*当前结点和前趋比较*/ predt=T->data;/*修改当前结点的前趋值*/return(bsbtr(T->rchild));/*判断右子树并返回最终结果*/}}7.11 (1)使用线性探查再散列法来构造散列表如表下所示散列表───────────────────────────────地址 0 1 2 3 4 5 6 7 8 9 10───────────────────────────────数据 33 1 13 12 34 38 27 22───────────────────────────────(2)使用链地址法来构造散列表如下图(3)装填因子a=8/11使用线性探查再散列法查找成功所需的平均查找次数为Snl=0.5(1+1/(1-a))=0.5*(1+1/(1-8/11))=7/3使用线性探查再散列法查找不成功所需的平均查找次数为:Unl=0.5(1+1/(1-a)2)=0.5*(1+1/(1-8/11)2)=65/9 使用链地址法查找成功所需的平均查找次数为:Snc=l+a/2=1+8/22=15/11使用链地址法查找不成功所需的平均查找次数为: 'Unl=a+e-a=8/1l+e-8/117.12 分析:在等查区间的上、下界处设两个指针由此计算出中间元素的序号当中间元素大于给定值X时接下来到其低端区间去查找;当中间元素小于给定值X时接下来到其高端区间去查找;当中间元素等于给定值X时表示查找成功输出其序号Int binlist(sqtable Aint stkeytype X) /*t、s分别为查找区间的上、下界*/{ if(s<t) return(0);/*查找失败*/else{ mid=(S+t)/2;switCh(mid){case x<A.item[midJ.key: return(binlist(Asmid-lX));/*在低端区间上递归*/case x==A.item[mid].key: return(mid);/+查找成功*/ case x>A.item[mid].key: return(amid+ltX));/*在高端区间上递归*/}}}int sqsearch0 (sqtable Akeytype X) /*数组有元素n个*/{ i=l;A.item[n+1].key=X;/t设置哨兵*/while (A.item[n+1].key!=X) i++;return (i% (n/1));/*找不到返回0找到返回其下标*/}查找成功平均查找长度为:(1+2+3+...+n)/n:(1+n)/2查找不成功平均查找长度为:n+17.14散列函数:H(key)=100+(key个位数+key十位数) mod l0;形成的散列表:100 101 102 103 104 105 106 107 108 10998 75 63 46 49 79 61 53 17查找成功时的平均长度为:(1+2+1+1+5+1+1+5+5+3)/10=2.5次由于长度为10的哈希表已满因此在插人第11个记录时所需作的比较次数的期望值为10查找不成功时的平均长度为10习题 8参考答案8.1 选择题(1)B (2)A (3)D (4)C (5)B (6)A (7)B (8)C (9)A (10)C(11)D (12)C (13) C (14)D (15)C (16)B (17) D (18)C (19)B (20)D8.2填空题(1)快速归并(2) O(log2n)O(nlog2n)(3)归并(4)向上根结点(5) 1918162030(6)(7)4913275076386597(8)88(9)插入选择(每次选择最大的)(10)快速归并(11)O(1)O(nlog2n)(12)稳定(13)3(14)(15205040)(15)O(log2n)(16)O(n2)(17)冒泡排序快速排序(18)完全二叉树n/2(19)稳定不稳定(20)24(2015)8.3. 假定给定含有n个记录的文件(r1f2...rn)其相应的关键字为(k1k2...kn)则排序就是确定文件的一个序列rrr2...rn使得k1'≤k2'≤...≤kn'从而使得文件中n个记录按其对应关键字有序排列如果整个排序过程在内存中进行则排序叫内部排序假设在待排序的文件中存在两个或两个以上的记录具有相同的关键字若采用某种排序方法后使得这些具有相同关键字的记录在排序前后相对次序依然保持不变则认为该排序方法是稳定的否则就认为排序方法是不稳定的8.4.稳定的有:直接插入排序、二分法插入排序、起泡排序、归并排序和直接选择排序8.5.初始记录序列按关键字有序或基本有序时比较次数为最多8.6.设5个元素分别用abcde表示取a与b、c与d进行比较若a>bc>d(也可能是a<bc<d此时情况类似)显然此时进行了两次比较取b与d再比较若b>d则a>b>d若b<d则有c>d>b此时已进行了3次比较要使排序比较最多7次可把另外两个元素按折半检索排序插入到上面所得的有序序列中此时共需要4次比较从而可得算法共只需7次比较8.7.题目中所说的几种排序方法中其排序速度都很快但快速排序、归并排序、基数排序和Shell排序都是在排序结束后才能确定数据元素的全部序列而排序过程中无法知道部分连续位置上的最终元素而堆排序则是每次输出一个堆顶元素(即最大或最少值的元素)然后对堆进行再调整保证堆顶元素总是当前剩下元素的最大或最小的从而可知欲在一个大量数据的文件中如含有15000个元素的记录文件中选取前10个最大的元素可采用堆排序进行8.8.二分法排序8.9.void insertsort(seqlist r)  ;{ //对顺序表中记录R[0一N-1)按递增序进行插入排序&NBSP;int ij;  ;for(i=n-2;i>=0; i--) //在有序区中依次插入r[n-2]..r[0]  ;if(r[i].key>r[i+1].key) //若不是这样则r[i]原位不动 ;{  ;r[n]=r[i];j=i+l;//r[n]是哨兵 ;do{ //从左向右在有序区中查找插入位置 ;r[j-1]= r[j];//将关键字小于r[i].key的记录向右移 ;j++;  ;}whle(r[j].key r[j-1]=r[n];//将引i)插入到正确位置上 ;}//endif ;}//insertsort.  ;8.10.建立初始堆:[937 694 863 265 438 751 742129075 3011]&NBSP;&NBSP;第一次排序重建堆:[863 694 751 765 438 301 742 129 075]9378.11.在排序过程中每次比较会有两种情况出现若整个排序过程至少需作t次比较则显然会有2^t个情况由于n个结点总共有n!种不同的排列因而必须有n!种不同的比较路径于是: 2t≥n!即t≥log2n!因为log2nl=nlog2n-n/ln2+log2n/2+O(1)故有log2n!≈nlog2n从而t≧nlog2n得证8.12.依据堆定义可知:序列(1)、(2)、(4)是堆(3)不是堆从而可对其调整使之为如下的大根堆(1009580604095821020)8.13.第一趟:[265 301] [129 751] [863 937] [694 742] [076 438]&NBSP; &NBSP;第二趟:[129 265 301 751] [694 742 863 937] [076 438]&NBSP;&NBSP;第三趟:[129 265 301 694 742 751 863 937] [076 438]&NBSP;&NBSP;第四趟:[076 129 265 301 438 694 742 751 863 937]&NBSP;8.14.(1)归并排序:(1829) (2547) (1258) (1051)(18252947) (10125158)(1012182529475158)(2)快速排序:(1018251229585147)(1018251229475158)(1012182529475158)(3)堆排序:初始堆(大顶堆):(58 47512918122510)第一次调整:(51 472529181210)(58)第二次调整:(47 2925101812)(5158)第三次调整:(29 18251012)(475158)第四次调整:(25 181210)(29475158)第五次调整:(18 1012)(2529475158)第六次调整:(12 10) (182529475158)第七次调整:(10 12182529475158)8.15.(1)直接插入排序序号 1 2 3 4 5 6 7 8 9 10 11 12 关键字 83 40 63 13 84 35 96 57 39 79 61 151=2 40 83 [63 13 84 35 96 57 39 79 61 15] 1=3 40 63 83 [13 84 35 96 57 39 79 61 15] 1=4 13 40 63 83 [84 3 5 96 57 39 79 61 15] I=5 13 40 63 83 84 [35 96 57 39 79 61 15] I=6 13 35 40 63 83 84 [96 57 39 79 61 15] 1=7 13 35 40 63 83 84 96 [57 39 79 61 15] 1=8 13 35 40 57 63 83 84 96 [ 39 79 61 15] 1=9 13 35 39 40 57 63 83 84 96 [79 61 15] I=10 13 35 39 40 57 63 79 83 84 96 [61 15] I=11 13 35 39 40 57 61 63 79 83 84 96 [15] 1=12 13 15 35 39 40 57 61 63 79 83 84 96 (2)直接选择排序序号 1 2 3 4 5 6 7 8 9 10 11 12 关键字 83 40 63 13 84 35 96 57 39 79 61 15i=1 13 [ 40 63 83 84 35 96 57 39 79 61 15] i=2 13 15 [63 83 84 35 96 57 39 79 61 40] i=3 13 15 35 [83 84 63 96 57 39 79 61 40] i=4 13 15 35 39 [84 63 96 57 83 79 61 40] i=5 13 15 35 39 40 [63 96 57 83 79 61 84] i=6 13 15 35 39 40 57 [96 63 83 79 61 84] i=7 13 15 35 39 40 57 61 [63 83 79 96 84] i=8 13 15 35 39 40 57 61 63 [83 79 96 84] i=9 13 15 35 39 40 57 61 63 79 183 96 84] i=10 13 15 35 39 40 57 61 63 79 83 [96 84] i=11 13 15 35 39 40 57 61 63 79 83 84 [96] (3)快速排序关键字 83 40 63 13 84 35 96 57 39 79 61 15 第一趟排序后 [15 40 63 13 61 35 79 57 39] 83 [96 84] 第二趟排序后 [13] 15 [63 40 61 35 79 57 39] 83 84 [96] 第三趟排序后 13 15 [39 40 61 35 57] 63 [79] 83 84 96 第四趟排序后 13 15 [35] 39 [61 40 57] 63 79 83 84 96第五趟排序后 13 15 35 39 [57 40] 61 63 79 83 84 96 第六趟排序后 13 15 35 39 40 [57] 61 63 79 83 84 96 第七趟排序后 13 15 35 39 40 57 61 63 79 83 84 96 (4)堆排序关键字 83 40 63 13 84 35 96 57 39 79 61 15排序成功的序列 96 84 83 79 63 61 57 40 39 35 15 13(5)归并排序关键字 83 40 63 13 84 35 96 57 39 79 61 15 第一趟排序后 [40 83] [13 63] [3584] [57 96] [39 79] [15 61]第二趟排序后 [13 40 63 83] [35 57 84 96] [15 39 61 79] 第三趟排序后 [13 35 40 57 63 83 84 96]] [15 39 61 79] 第四趟排序后 13 15 35 39 40 57 61 63 79 83 84 96。
详解数据结构之散列(哈希)表
详解数据结构之散列(哈希)表1.散列表查找步骤散列表,最有用的基本数据结构之一。
是根据关键码的值直接进行访问的数据结构,散列表的实现常常叫做散列(hasing)。
散列是一种用于以常数平均时间执行插入、删除和查找的技术,下面我们来看一下散列过程。
我们的整个散列过程主要分为两步:1.通过散列函数计算记录的散列地址,并按此散列地址存储该记录。
就好比麻辣鱼,我们就让它在川菜区,糖醋鱼,我们就让它在鲁菜区。
但是我们需要注意的是,无论什么记录我们都需要用同一个散列函数计算地址,然后再存储。
2.当我们查找时,我们通过同样的散列函数计算记录的散列地址,按此散列地址访问该记录。
因为我们存和取的时候用的都是一个散列函数,因此结果肯定相同。
刚才我们在散列过程中提到了散列函数,那么散列函数是什么呢?我们假设某个函数为f,使得存储位置= f (key) ,那样我们就能通过查找关键字不需要比较就可获得需要的记录的存储位置。
这种存储技术被称为散列技术。
散列技术是在通过记录的存储位置和它的关键字之间建立一个确定的对应关系 f ,使得每个关键字key 都对应一个存储位置f(key)。
见下图这里的 f 就是我们所说的散列函数(哈希)函数。
我们利用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间就是我们本文的主人公------散列(哈希)上图为我们描述了用散列函数将关键字映射到散列表。
但是大家有没有考虑到这种情况,那就是将关键字映射到同一个槽中的情况,即f(k4) = f(k3) 时。
这种情况我们将其称之为冲突,k3 和k4 则被称之为散列函数 f 的同义词,如果产生这种情况,则会让我们查找错误。
幸运的是我们能找到有效的方法解决冲突。
首先我们可以对哈希函数下手,我们可以精心设计哈希函数,让其尽可能少的产生冲突,所以我们创建哈希函数时应遵循以下规则:1.必须是一致的。
假设你输入辣子鸡丁时得到的是在看,那么每次输入辣子鸡丁时,得到的也必须为在看。
数据结构和算法课程设计题目
北方民族大学课程设计课程名称:数据结构与算法院(部)名称:信息与计算科学学院组长姓名学号同组人员姓名指导教师姓名:纪峰设计时间:2010.6.7----2009.6.27一、《数据结构与算法》课程设计参考题目(一)参考题目一(每位同学选作一个,同组人员不得重复)1、编写函数实现顺序表的建立、查找、插入、删除运算。
2、编写函数分别实现单链表的建立、查找、插入、删除、逆置算法。
3、编写函数实现双向链表的建立、插入、删除算法。
4、编写函数实现顺序栈的进栈、退栈、取栈顶的算法。
5、编写函数实现链栈的进栈、退栈、取栈顶的算法。
6、编写函数实现双向顺序栈的判空、进栈、出栈算法。
7、编写函数实现循环队列的判队空、取队头元素、入队、出队算法。
8、编写函数实现链环队列的判队空、取队头节点、入队、出队算法。
9、编写函数实现串的,求串长、连接、求字串、插入、删除等运算。
10、分别实现顺序串和链串的模式匹配运算。
11、实现二叉树的建立,前序递归遍历和非递归遍历算法。
12、实现二叉树的建立,中序递归遍历和非递归遍历算法。
13、实现二叉树的建立,后序递归遍历和非递归遍历算法。
14、实现二叉树的中序线索化,查找*p结点中序下的前驱和后继结点。
15、分别以临接表和邻接矩阵作为存储就够实现图的深度优先搜索和广度优先搜索算法。
16、利用线性探测处理冲突的方法实现散列表的查找和插入算法。
(二)参考题目二(每三人一组,任选三个题目完成)1.运动会分数统计(限1人完成)任务:参加运动会有n个学校,学校编号为1……n。
比赛分成m个男子项目,和w个女子项目。
项目编号为男子1……m,女子m+1……m+w。
不同的项目取前五名或前三名积分;取前五名的积分分别为:7、5、3、2、1,前三名的积分分别为:5、3、2;哪些取前五名或前三名由学生自己设定。
(m<=20,n<=20)功能要求:1)可以输入各个项目的前三名或前五名的成绩;2)能统计各学校总分,3)可以按学校编号或名称、学校总分、男女团体总分排序输出;4)可以按学校编号查询学校某个项目的情况;可以按项目编号查询取得前三或前五名的学校。
《数据结构》实验指导书(C语言版)(浦江学院)
实验1: 顺序表的操作实验一、实验名称和性质二、实验目的1.掌握线性表的顺序存储结构的表示和实现方法。
2.掌握顺序表基本操作的算法实现。
3.了解顺序表的应用。
三、实验内容1.建立顺序表。
2.在顺序表上实现插入、删除和查找操作(验证性内容)。
3.删除有序顺序表中的重复元素(设计性内容)。
四、实验的软硬件环境要求硬件环境要求:PC机(单机)使用的软件名称、版本号:Windows环境下的VC++6.0五、知识准备前期要求熟练掌握了C语言的编程规则、方法和顺序表的基本操作算法。
六、验证性实验1.实验要求编程实现如下功能:(1)根据输入顺序表的长度n和各个数据元素值建立一个顺序表,并输出顺序表中各元素值,观察输入的内容与输出的内容是否一致。
(2)在顺序表的第i个元素之前插入一个值为x的元素,并输出插入后的顺序表中各元素值。
(3)删除顺序表中第i个元素,并输出删除后的顺序表中各元素值。
(4)在顺序表中查找值为e的数据元素,如果查找成功,则显示“查找成功”和该元素在顺序表中的位置,否则显示“查找失败”。
2. 实验相关原理线性表的顺序存储结构称为顺序表,顺序表的存储结构描述为:#define MAXLEN 30 /*线性表的最大长度*/typedef struct{Elemtype elem[MAXLEN]; /*顺序表中存放元素的数组,其中elemtype为抽象数据类型,在程序具体实现时可以用任意类型代替*/int length; /*顺序表的长度,即元素个数*/}Sqlist; /*顺序表的类型*/【核心算法提示】(1)顺序表插入操作的基本步骤:要在顺序表中的第i个数据元素之前插入一个数据元素x,首先要判断插入位置i是否合法,假设线性表的表长为n,则i的合法值范围:1≤i ≤n+1,若是合法位置,就再判断顺序表是否满,如果满,则增加空间或结束操作,如果不满,则将第i个数据元素及其之后的所有数据元素都后移一个位置,此时第i个位置已经腾空,再将待插入的数据元素x插入到该位置上,最后将线性表的表长增加1。
散列表---实现个人信息管理
散列表---实现个人信息管理一、数据结构个人信息:至少五个域散列表:以姓名为关键字,平均查找长度不超过2.5,确定表大小,设计散列函数,冲突处理方法(建议采用拉链法)。
文件:个人信息以文件形式保存二、基本算法插入个人信息删除个人信息按关键字查找个人信息按非关键字查找个人信息统计两种查找过程的平均查找长度三、功能要求读文件数据建立散列表保存散列表到文件散列表遍历修改个人信息(要求以菜单驱动)四、上机时间18、19周:每天下午2:30~6:00五、设计报告要求封面内容A4手写六、交报告时间19周:周五下午3点计算机教研室一、课程设计的目的:1.了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;2.初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;3.提高综合运用所学的理论知识和方法独立分析和解决问题的能力;4.训练用系统的观点和软件开发一般规范进行软件开发,培养软件工作者所应具备的科学的工作方法和作风。
二、课程设计的基本要求:1.问题分析和任务定义:根据设计题目的要求,充分地分析和理解问题,明确问题要求做什么?(而不是怎么做?)限制条件是什么?2.逻辑设计:对问题描述中涉及的操作对象定义相应的数据类型,并按照以数据结构为中心的原则划分模块,定义主程序模块和各抽象数据类型。
逻辑设计的结果应写出每个抽象数据类型的定义(包括数据结构的描述和每个基本操作的功能说明),各个主要模块的算法,并画出模块之间的调用关系图;3.详细设计:定义相应的存储结构并写出各函数的伪码算法。
在这个过程中,要综合考虑系统功能,使得系统结构清晰、合理、简单和易于调试,抽象数据类型的实现尽可能做到数据封装,基本操作的规格说明尽可能明确具体。
详细设计的结果是对数据结构和基本操作作出进一步的求精,写出数据存储结构的类型定义,写出函数形式的算法框架;4.程序编码:把详细设计的结果进一步求精为程序设计语言程序。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验课题:做这个实验时采用Open Addressing框架,也可加做Separate Chaining以形成比较。
1 构造散列表,把字符串数组中的各项加入到散列表中string MyBirds[13] = { "robin", "sparrow", "hawk", "eagle", "seagull", "bluejay", "owl", "cardinal", "Jakana", "Moa", "Egret", "Penguin", "hawk" };用C表示,可以是char * MyBirds[13] = { "robin", "sparrow", "hawk", "eagle", "seagull", "bluejay", "owl", "cardinal", "Jakana", "Moa", "Egret", "Penguin", "hawk" };为便于观察冲突现象,初始构造散列表时,表的容量不要过大,对Open Addressing,装载因子为0.5左右,对于Separate Chaining,装载因子为1左右即可。
也不要做rehash(应该改源代码的哪里,如何改)。
建议对源代码做些改动、增加一些输出(建议用条件编译控制这些输出),以便于观察冲突的发生和解决;对于Open Addressing,参考代码的冲突解决方案是用的平方探测(quadratic probing),如果用线性探测(linear probing)的策略,应该对函数findPos做什么修改(冲突解决的策略都集中在那里)#include<stdio.h>#include<stdlib.h>#include "hashquad.h"#include<string.h>#define MinTableSize 26typedef unsigned int Index;typedef Index Position;struct HashTbl;typedef struct HashTbl *HashTable;enum KindOfEntry { Legitimate, Empty, Deleted };struct HashEntry{char *Element;enum KindOfEntry Info;};typedef struct HashEntry Cell;struct HashTbl{int TableSize;Cell *TheCells;};static int NextPrime( int N ){int i;if( N % 2 == 0 )N++;for( ; ; N += 2 ){for( i = 3; i * i <= N; i += 2 )if( N % i == 0 )goto ContOuter;return N;ContOuter: ;}}Index Hash( const char *Key, int TableSize ){return *Key % TableSize;}HashTable InitializeTable( int TableSize ){HashTable H;int i;/* 1*/ if( TableSize < MinTableSize ){/* 2*/ printf( "Table size too small" );/* 3*/ return NULL;}/* Allocate table *//* 4*/ H = (struct HashTbl *)malloc( sizeof( struct HashTbl ) );/* 5*/ if( H == NULL )/* 6*/ printf( "Out of space" );/* 7*/ H->TableSize = NextPrime( TableSize );/* Allocate array of Cells *//* 8*/ H->TheCells = (struct HashEntry *)malloc( sizeof( Cell ) * H->TableSize );/* 9*/ if( H->TheCells == NULL )/*10*/ printf( "Out of space" );/*11*/ for( i = 0; i < H->TableSize; i++ ){H->TheCells[i].Element=(char *)malloc(10*sizeof(char));H->TheCells[i].Info=Empty;}/*12*//*13*/ return H;}Position Find( char *Key, HashTable H ){Position CurrentPos;int CollisionNum;/* 1*/ CollisionNum = 0;/* 2*/ CurrentPos = Hash( Key, H->TableSize );//printf("%d\n",CurrentPos);/* 3*/ while( H->TheCells[ CurrentPos ].Info != Empty &&strcmp(H->TheCells[ CurrentPos ].Element,Key)!=0 )/* Probably need strcmp!! */{if (H->TheCells[ CurrentPos ].Element!= NULL)printf("冲突: %s and %s\n", H->TheCells[ CurrentPos ].Element,Key);/* 4*/ CurrentPos += 2 * ++CollisionNum - 1;/* 5*/ if( CurrentPos >= H->TableSize )/* 6*/ CurrentPos -= H->TableSize;}/* 7*/ return CurrentPos;}void Insert( char *Key, HashTable H ){Position Pos;Pos = Find( Key, H );if( H->TheCells[ Pos ].Info != Legitimate ){/* OK to insert here */H->TheCells[ Pos ].Info = Legitimate;strcpy(H->TheCells[ Pos ].Element,Key);/* Probably need strcpy! */}}/*char*Retrieve( Position P, HashTable H ){return H->TheCells[ P ].Element;}*/void DestroyTable( HashTable H ){free( H->TheCells );free( H );}void main(){int i,x,n;char s[10];HashTable H;char * MyBirds[13] = { "robin", "sparrow", "hawk", "eagle", "seagull", "bluejay", "owl", "cardinal", "Jakana", "Moa", "Egret", "Penguin", "hawk" };printf(" \n");printf("原来的MyBirds:\n\n");printf(" 字符串位置\n");for(i=0;i<13;i++)printf("%8s: %2d\n",MyBirds[i],i+1);/*printf(" \n");printf("生成散列表:\n");n=Hash( Key, H->TableSize );for(i=0;i<13;i++)printf("%8s: %2d\n",MyBirds[i],i+1);*/H=InitializeTable( 29 );printf(" \n");printf("生成散列表:\n\n");printf(" 字符串散列值位置\n");for(i=0;i<13;i++)Insert(MyBirds[i] , H );for(i=0;i<29;i++){if(H->TheCells[i].Info!=Empty)printf("%8s: %2d %d\n",H->TheCells[i].Element,x=Hash(H->TheCells[i].Element,29),n=Find( H->TheCells[i].Element,H));}printf("请输入要查找的值:");scanf("%s",s);for(i=0;i<29;i++){if(strcmp(H->TheCells[i].Element,s)==0)break;}if(i<29)printf("查找成功,位置在:%d\n ",Find( s,H));else printf("查找失败\n");DestroyTable( H );}。