第一课:数据结构的基本概念和术语
第二课:抽象数据类型的表示与实现
第三课:算法及算法设计要求
第四课:算法效率的度量和存储空间需求
第五课:线性表的类型定义
第六课:线性表的顺序表示和实现
第七课:实验一
线性表的顺序存储实验
第八课:线性表的链式表示与实现
第九课:循环链表与双向链表
第十课:栈的表示与实现
第十一课:栈的应用
第十二课:实验二
循环链表实验
第十三课:队列
第十四课:串的定义
第十五课:串的表示和实现
第十六课:串操作应用举例
第十七课:实验三:栈的表示与实现及栈的应用
第十八课:数组的顺序表示与实现
第十九课:实验四
串的实现实验
第二十课:广义表
第二十一课:树、二叉树定义及术语
第二十二课:实验五
数组实验
第二十三课:二叉树的存储结构
第二十四课:遍历二叉树
第二十五课:单元测验
第二十六课:图的定义与术语
第二十七课:实验六
二叉树实验
第二十八课:图的存储结构
第二十九课:静态查找表(一)顺序表的查找
第三十课:静态查找表(二)有序表的查找
第三十一课:动态查找表
第三十二课:哈希表(一)
第三十三课:哈希表(二)
第三十四课:插入排序,快速排序
第三十五课:实验七
查找
第三十六课:选择排序,归并排序
第三十七课:实验八
排序实验
第三十八课:文件概念,顺序文件
第三十九课:索引文件
第四十课:总复习
|
学号
|
姓名
|
语文
|
数学
|
C语言
|
6201001
|
张三
|
85
|
54
|
92
|
6201002
|
李四
|
92
|
84
|
64
|
6201003
|
王五
|
87
|
74
|
73
|
6201004
|
|
|
|
|
...
|
|
|
|
|
|
特征
|
示例
|
集合
|
元素间为松散的关系
|
|
线性结构
|
元素间为严格的一对一关系
|
如上面的成绩表中各元素
|
树形结构
|
元素间为严格的一对多关系
|
|
图状结构(或网状结构)
|
元素间为多对多关系
|
|
逻辑结构
|
|
“数据结构”定义中的“关系”指数据间的逻辑关系,故也称数据结构为逻辑结构。
|
存储结构
|
|
数据结构在计算机中的表示称为物理结构。又称存储结构。
|
顺序存储结构
|
||
链式存储结构
|
|
特征
|
例
|
原子类型
|
值在逻辑上不可分解
|
int float
|
结构类型
|
值由若干成分按某种结构组成
|
struct stu
|
抽象数据类型分类
|
|
原子类型
|
值不可分解,如int
|
固定聚合类型
|
值由确定数目的成分按某种结构组成,如复数
|
可变聚合类型
|
值的成分数目不确定如学生基本情况
|
名称
|
线性表
|
|
数据对象
|
D={a
i
| a
i
(-ElemSet,i=1,2,...,n,n>=0}
|
任意数据元素的集合
|
数据关系
|
除第一个和最后一个外,每个元素有唯一的直接前趋和唯一的直接后继
|
|
基本操作
|
ListInsert(&L,i,e)
|
L为线性表,i为位置,e为数据元素。
|
ListDelete(&L,i,e)
|
||
...
|
类C语言语法示例
|
|
|
|||
1、预定义常量和类型
|
#define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #define OVERFLOW -2 typedef in Status; //Status是函数的类型,其值是函数结果状态代码。 |
|
|||
2、数据结构的存储结构
|
typedef ElemType first;
|
|
|||
3、基本操作的算法
|
函数类型 函数名(函数参数表){ //算法说明 语句序列 }//函数名 |
|
|||
4、赋值语句
|
简单赋值:
|
变量名=表达式;
|
|
||
串联赋值:
|
变量名1=变量名2=...=变量名k=表达式;
|
|
|||
成组赋值:
|
(变量名1,...,变量名k)=(表达式1,...,表达式k); 结构名=结构名; 结构名=(值1,...,值k); 变量名[]=表达式; 变量名[起始下标..终止下标]=变量名[起始下标..终止下标]; |
||||
交换赋值:
|
变量名<-->变量名;
|
|
|
||
条件赋值:
|
变量名=条件表达式?表达式?表达式T:表达式F
|
|
|
||
5、选择语句
|
1、if(表达式) 语句;
2、if(表达式) 语句; else 语句; 3、switch(表达式){ case 值1:语句序列1;break;
...
case 值n:语句序列n;break; default:语句序列n+1;break; } 4、switch{ case 条件1:语句序列1;break;
... case 条件n:语句序列n;break; default:语句序列n+1;break; } |
|
|
||
6、循环语句
|
for(赋初值表达式;条件;修改表达式序列)语句; while(条件)语句; do{ 语句序列}while(条件); |
|
|
||
7、结束语句
|
return [表达式]; return; //函数结束语句 break; //case结束语句 exit(异常代码); //异常结束语句 |
|
|
||
8、输入和输出语句
|
scanf([格式串],变量1,...,变量n);
|
|
|
||
9、注释
|
//文字序列
|
|
|
||
10、基本函数
|
max(表达式1,...,表达式n) min,abs,floor,ceil,eof,eoln |
|
|
||
11、逻辑运算
|
&&与运算;||或运算
|
|
|
#define ERROR 0
#define OK 1 struct STU { char name[20]; char stuno[10]; int age; int score; }stu[50]; struct LIST { struct STU stu[50]; int length; }L; int printlist(struct LIST L) { int i; printf("name stuno age score/n"); for(i=0;i printf("/n"); } int listinsert(struct LIST *L,int i,struct STU e) { struct STU *p,*q; if (i<1||i>L->length+1) return ERROR; q=&(L->stu[i-1]); for(p=&L->stu[L->length-1];p>=q;--p) *(p+1)=*p; *q=e; ++L->length; return OK; }/*ListInsert Before i */ main() { struct STU e; L.length=0; strcpy(e.name,"zmofun"); strcpy(e.stuno,"100001"); e.age=80; e.score=1000; listinsert(&L,1,e); printlist(L); printf("List length now is %d./n/n",L.length);
strcpy(e.name,"bobjin"); strcpy(e.stuno,"100002"); e.age=80; e.score=1000; listinsert(&L,1,e); printlist(L); printf("List length now is %d./n/n",L.length); } |
E:/ZM/Zmdoc/datastru/class02>listdemo
name stuno age score
zmofun 100001 80 1000
List length now is 1.
name stuno age score
bobjin 100002 80 1000
zmofun 100001 80 1000
List length now is 2.
|
有穷性
|
一个算法必须总是(对任何合法的输入值)在执行有穷步之后结束,且每一步都可在有穷时间内完成;
|
确定性
|
算法中每一条指令必须有确切的含义,读者理解时不会产生二义性。有任何条件下,算法只有唯一的一条执行路径,即对于相同的输入只能得出相同的输出。
|
可行性
|
一个算法是能行的,即算法中描述的操作都是可以通过已经实现的基本运算执行有限次来实现的。
|
输入
|
一个算法有零个或多个的输入,这些输入取自于某个特定的对象的集合。
|
输出
|
一个算法有一个或多个的输出。这些输出是同输入有着某些特定关系的量。
|
有穷性
|
haha() {/*only a joke,do nothing.*/ } main() {printf("请稍等...您将知道世界的未日..."); while(1) haha(); } |
确定性
|
float average(int *a,int num) {int i;long sum=0; for(i=0;i return sum/num; } main() {int score[10]={1,2,3,4,5,6,7,8,9,0}; printf("%f",average(score,10); } |
可行性
|
|
输入
|
|
输出
|
getsum(int num) { int i,sum=0; for(i=1;i<=num;i++) sum+=i; } /*无输出的算法没有任何意义, |
算法正确性的四个层次
|
|
程序不含语法错误。
|
max(int a,int b,int c) { if (a>b) {if( a>c ) return c ; else return a ; } } |
程序对于几组输入数据能够得出满足规格说明要求的结果。
|
max(int a,int b,int c) { if (a>b) {if(a>c) return a; else return c; } } /* 8,6,7 */ /* 9,3,2 */ |
程序对于精心选择的典型、苛刻而带有刁难性的几组输入数据能够得出满足规格说明要求的结果。
|
max(int a,int b,int c) { if (a>b) {if(a>c) return a; else return c; } else {if(b>c) return b; else return c; } } |
程序对于一切合法的输入数据都能产生满足规格说明要求的结果。
|
|
|
算法一
|
算法二
|
在三个整数中求最大者
|
max(int a,int b,int c) {if (a>b) {if(a>c) return a; else return c; } else {if(b>c) return b; else return c; }/*无需额外存储空间,只需两次比较*/ |
max(int a[3]) {int c,int i; c=a[0]; for(i=1;i<3;i++) if (a[i]>c) c=a[i]; return c; } /*需要两个额外的存储空间,两次比较,至少一次赋值*/ /*共需5个整型数空间*/ |
求100个整数中最大者
|
同上的算法难写,难读
|
max(int a[
100
]) {int c,int i; c=a[0]; for(i=1;i< 100 ;i++) if (a[i]>c) c=a[i]; return c; } /*共需102个整型数空间*/ |
程序在计算机上运行所需时间的影响因素
|
|
算法本身选用的策略
|
|
问题的规模
|
规模越大,消耗时间越多
|
书写程序的语言
|
语言越高级,消耗时间越多
|
编译产生的机器代码质量
|
|
机器执行指令的速度
|
|
求4*4矩阵元素和,T(4)=O(f(4))
f=n*n;
|
sum(int num[4][4])
{ int i,j,r=0;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
r+=num[i][j]; /*
原操作
*/
return r; } |
最好情况:
T(4)=O(0)
最坏情况: T(4)=O(n*n) |
ispass(int num[4][4])
{ int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
if(num[i][j]!=i*4+j+1)
return 0;
return 1; } |
语句
|
频度
|
时间复杂度
|
{++x;s=0;}
|
1
|
O(1)
|
for(i=1;i<=n;++i)
{++x;s+=x;}
|
n
|
O(n)
|
for(j=1;j<=n;++j)
for(k=1;k<=n;++k)
{++x;s+=x;}
|
n*n
|
O(n*n)
|
|
|
O(log n)
|
|
|
|
基本操作的执行次数不确定时的时间复杂度
|
|
平均时间复杂度
|
依基本操作执行次数概率计算平均
|
最坏情况下时间复杂度
|
在最坏情况下基本操作执行次数
|
在数据元素的非空有限集中,
(1)存在唯一的一个被称做“第一个”的数据元素;
(2)存在唯一的一个被称做“最后一个”的数据元素;
(3)除第一个之外,集合中的每个数据元素均只有一个前驱;
(4)除最后一个之外,集合中每个数据元素均只有一个后继。
|
|
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
|
|
|
|
|
|
|
学号
|
姓名
|
语文
|
数学
|
C语言
|
6201001
|
张三
|
85
|
54
|
92
|
6201002
|
李四
|
92
|
84
|
64
|
6201003
|
王五
|
87
|
74
|
73
|
6201004
|
|
|
|
|
...
|
|
|
|
|
a
1
|
...
|
a
i-1
|
a
i
|
a
i+1
|
...
|
a
n
|
-------------------List Demo is running...----------------
First is InsertList function. name stuno age score stu1 100001 80 1000 stu2 100002 80 1000 List A length now is 2. name stuno age score stu1 100001 80 1000 stu2 100002 80 1000 stu3 100003 80 1000 List A length now is 3. name stuno age score zmofun 100001 80 1000 bobjin 100002 80 1000 stu1 100001 80 1000 List B length now is 3.
Second is UnionList function.
Now union List A and List B..... name stuno age score stu1 100001 80 1000 stu2 100002 80 1000 stu3 100003 80 1000 zmofun 100001 80 1000 bobjin 100002 80 1000 List A length now is 5.
Welcome to visit http://zmofun.heha.net !
|
逻辑结构
|
|
“数据结构”定义中的“关系”指数据间的逻辑关系,故也称数据结构为逻辑结构。
|
存储结构
|
|
数据结构在计算机中的表示称为物理结构。又称存储结构。
|
顺序存储结构
|
||
链式存储结构
|
|
|
a[9]
|
|
线性表的动态分配顺序存储结构
|
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10 typedef struct{
ElemType *elem; //存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量以一数据元素存储长度为单位
}SqList;
|
序号
|
数据元素
|
序号
|
数据元素
|
|
序号
|
数据元素
|
序号
|
数据元素
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
<- 25 |
|
|
|
|
|
->
24
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
插入前n=8;插入后n=9;
|
|
删除前n=8;删除后n=7;
|
顺序表的插入算法
|
status ListInsert(List *L,int i,ElemType e) {
struct STU *p,*q;
if (i<1||i>L->length+1) return ERROR;
q=&(L->elem[i-1]);
for(p=&L->elem[L->length-1];p>=q;--p)
*(p+1)=*p;
*q=e;
++L->length;
return OK;
}/*ListInsert Before i */
|
顺序表的合并算法
|
void MergeList(List *La,List *Lb,List *Lc) {
ElemType *pa,*pb,*pc,*pa_last,*pb_last;
pa=La->elem;pb=Lb->elem;
Lc->listsize = Lc->length = La->length + Lb->length;
pc = Lc->elem =
(ElemType *)malloc(Lc->listsize * sizeof(ElemType));
if(!Lc->elem) exit(OVERFLOW);
pa_last = La->elem + La->length - 1;
pb_last = Lb->elem + Lb->length - 1;
while(pa<=pa_last && pb<=pb_last) {
if(Less_EqualList(pa,pb)) *pc++=*pa++;
else *pc++=*pb++;
}
while(pa<=pa_last) *pc++=*pa++;
while(pb<=pb_last) *pc++=*pb++;
}
|
顺序表的查找算法
|
int LocateElem(List *La,ElemType e,int type) {
int i;
switch (type) {
case EQUAL:
for(i=0;i
if(EqualList(&La->elem[i],&e))
return 1;
break;
default:
break;
}
return 0;
}
|
顺序表的联合算法
|
void UnionList(List *La, List *Lb) {
int La_len,Lb_len; int i; ElemType e;
La_len=ListLength(La); Lb_len=ListLength(Lb);
for(i=0;i
GetElem(*Lb,i,&e);
if(!LocateElem(La,e,EQUAL))
ListInsert(La,++La_len,e);
}
}
|
|
|
|
Status ListDelete_DuL(DuLinkList &L,int i,ElemType &e){
if(!(p=GetElemP_DuL(L,i)))
return ERROR;
e=p->data;
p->prior->next=p->next;
p->next->prior=p->pror;
free(p);
return OK;
}//ListDelete_DuL
|
Status ListInsert_DuL(DuLinkList &L,int i,ElemType &e){
if(!(p=GetElemP_DuL(L,i)))
return ERROR;
if(!(s=(DuLinkList)malloc(sizeof(DuLNode)))) return ERROR;
s->data=e;
s->prior=p->prior;
p->prior->next=s;
s->next=p;
p->prior=s;
return OK;
}//ListInsert_DuL
|
typedef struct LNode{
ElemType data;
struct LNode *next;
}*Link,*Position;
typedef struct{
Link head,tail;
int len;
}LinkList;
Status MakeNode(Link &p,ElemType e);
//分配由p指向的值为e的结点,并返回OK;若分配失败,则返回ERROR
void FreeNode(Link &p);
//释放p所指结点
Status InitLinst(LinkList &L);
//构造一个空的线性链表L
Status DestroyLinst(LinkList &L);
//销毁线性链表L,L不再存在
Status ClearList(LinkList &L);
//将线性链表L重置为空表,并释放原链表的结点空间
Status InsFirst(Link h,Link s);
//已知h指向线性链表的头结点,将s所指结点插入在第一个结点之前
Status DelFirst(Link h,Link &q);
//已知h指向线性链表的头结点,删除链表中的第一个结点并以q返回
Status Append(LinkList &L,Link s);
//将指针s所指(彼此以指针相链)的一串结点链接在线性链表L的最后一个结点
//之后,并改变链表L的尾指针指向新的尾结点
Status Remove(LinkList &L,Link &q);
//删除线性链表L中的尾结点并以q返回,改变链表L的尾指针指向新的尾结点
Status InsBefore(LinkList &L,Link &p,Link s);
//已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之前,
//并修改指针p指向新插入的结点
Status InsAfter(LinkList &L,Link &p,Link s);
//已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之后,
//并修改指针p指向新插入的结点
Status SetCurElem(Link &p,ElemType e);
//已知p指向线性链表中的一个结点,用e更新p所指结点中数据元素的值
ElemType GetCurElem(Link p);
//已知p指向线性链表中的一个结点,返回p所指结点中数据元素的值
Status ListEmpty(LinkList L);
//若线性链表L为空表,则返回TRUE,否则返回FALSE
int ListLength(LinkList L);
//返回线性链表L中的元素个数
Position GetHead(LinkList L);
//返回线性链表L中头结点的位置
Position GetLast(LinkList L);
//返回线性链表L中最后一个结点的位置
Position PriorPos(LinkList L,Link p);
//已知p指向线性链表L中的一个结点,返回p所指结点的直接前趋的值
//若无前趋,返回NULL
Position NextPos(LinkList L,Link p);
//已知p指向线性链表L中的一个结点,返回p所指结点的直接后继的值
//若无后继,返回NULL
Status LocatePos(LinkList L,int i,Link &p);
//返回p指示线性链表L中第i个结点的位置并返回OK,i值不合法时返回ERROR
Position LocateElem(LinkList L,ElemType e,
Status(*compare)(ElemType,ElemType));
//返回线性链表L中第1个与e满足函数compare()判定关系的元素的位置,
//若下存在这样的元素,则返回NULL
Status ListTraverse(LinkList L,Status(*visit)());
//依次对L的每个元素调用函数visit()。一旦visit()失败,则操作失败。
|
void conversion() {
pSqStack S;
SElemType e;
int n;
InitStack(&S);
printf("Input a number to convert to OCT:/n");
scanf("%d",&n);
if(n<0)
{ printf("/nThe number must be over 0.");
return;}
if(!n) Push(S,0);
while(n){
Push(S,n%8);
n=n/8; }
printf("the result is: ");
while(!StackEmpty(*S)){
Pop(S,&e); printf("%d",e);}
}
|
void LineEdit() {
pSqStack S,T; char str[1000];
int strlen=0; char e; char ch;
InitStack(&S);
InitStack(&T);
ch=getchar();
while(ch!=EOFILE) {
while(ch!=EOFILE&&ch!='/n') {
switch(ch){
case '#': Pop(S,&ch); break;
case '@': ClearStack(S); break;
default: Push(S,ch); break; }
ch=getchar();
}
if(ch=='/n') Push(S,ch);
while(!StackEmpty(*S)) { Pop(S,&e); Push(T,e); }
while(!StackEmpty(*T)) { Pop(T,&e); str[strlen++]=e; }
if(ch!=EOFILE) ch=getchar();
}
str[strlen]='/0';
printf("/n%s",str);
DestroyStack(S);
DestroyStack(T);
}
|
char EvaluateExpression() {
SqStack *OPND,*OPTR;
char c,x,theta; char a,b;
InitStack(&OPTR); Push(OPTR,'#');
InitStack(&OPND);
c=getchar();
while(c!='#'||GetTop(*OPTR)!='#') {
if(!In(c,OP)) {Push(OPND,c);c=getchar();}
else
switch(Precede(GetTop(*OPTR),c)) {
case '<': Push(OPTR,c); c=getchar(); break;
case '=': Pop(OPTR,&x); c=getchar(); break;
case '>': Pop(OPTR,&theta);
Pop(OPND,&b); Pop(OPND,&a);
Push(OPND,Operate(a,theta,b));
break;
}
}
c=GetTop(*OPND);
DestroyStack(OPTR);
DestroyStack(OPND);
return c;
}
|
|
|
a[0]
|
a[1]
|
a[2]
|
a[3]
|
a[4]
|
a[5]
|
...
|
a[n]
|
3
|
a
|
b
|
c
|
|
|
|
pascal
|
a
|
b
|
c
|
/0
|
|
|
|
c
|
S1,S2串长和小于最大值
|
S1,S2串长和超过最大串长
|
S1串长已等于最大串长
|
图一
|
图二
|
main(){
float a,b,max;
scanf("%f,%f",&a,&b);
if (a>b) max=a;
else max=b;
};
|
m
|
a
|
i
|
n
|
(
|
)
|
{
|
/n
|
|
|
f
|
l
|
o
|
a
|
t
|
|
a
|
,
|
b
|
,
|
m
|
a
|
x
|
;
|
/n
|
|
|
s
|
c
|
a
|
n
|
f
|
(
|
"
|
%
|
f
|
,
|
%
|
f
|
"
|
,
|
&
|
a
|
,
|
&
|
b
|
)
|
;
|
/n
|
|
|
i
|
f
|
|
a
|
>
|
b
|
|
|
m
|
a
|
x
|
=
|
a
|
;
|
/n
|
|
|
e
|
l
|
s
|
e
|
|
|
m
|
a
|
x
|
=
|
b
|
;
|
/n
|
}
|
/n
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a
00
|
a
01
|
a
02
|
...
|
a
0,n-1
|
a
10
|
a
11
|
a
12
|
...
|
a
1,n-1
|
...
|
...
|
...
|
...
|
...
|
a
m-1,0
|
a
m-1,1
|
a
m-1,2
|
...
|
a
m-1,n-1
|
A
0
|
|
||||||||||||||||||||
A
1
|
|||||||||||||||||||||
...
|
|||||||||||||||||||||
A
m
|
a
00
|
a
01
|
a
02
|
...
|
a
0,n-1
|
a
10
|
a
11
|
a
12
|
...
|
a
1,n-1
|
...
|
a
m-1,0
|
a
m-1,1
|
a
m-1,2
|
...
|
a
m-1,n-1
|
性质1:
|
在二叉树的第i层上至多有2的i-1次方个结点(i>=1)。
|
|
性质2:
|
深度为k的二叉树至多有2的k次方减1个结点(k>=1)。
|
|
性质3:
|
对任何一棵二叉树T,如果其终端结点数为n
0
,度为2的结点数为n
2
,则n
0
=n
2
+1。
|
|
性质4:
|
具有n个结点的完全二叉树的深度为|log
2
n
|+1
|
|
性质5:
|
如果对一棵有n个结点的完全二叉树的结点按层序编号,则对任一结点i(1=(1)如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则双亲PARENT(i)是结点i/2 (2)如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子LCHILD(i)是结点2i (3)如果2i+1>n,则结点i无右孩子;否则其右孩子RCHILD(i)是结点2i+1 |
|
结点编号
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
13
|
14
|
15
|
结点值
|
1
|
2
|
3
|
4
|
5
|
0
|
0
|
0
|
0
|
6
|
7
|
0
|
0
|
0
|
0
|
先序
|
1
|
访问根结点
|
2
|
先序访问左子树
|
|
3
|
先序访问右子树
|
|
中序
|
1
|
中序访问左子树
|
2
|
中序访问根结点
|
|
3
|
中序访问右子树
|
|
后序
|
1
|
后序访问左子树
|
2
|
后序访问右子树
|
|
3
|
访问根结点
|
|
v1与v2互为邻接点 e1依附于顶点v1和v2 v1和v2相关联 v1的度为3 |
表结点
|
|
|||
头结点
|
|
查找表:
|
是由同一类型的数据元素(或记录)构成的集合。
|
查找表的操作:
|
1、查询某个“特定的”数据元素是否在查找表中。 2、检索某个“特定的”数据元素的各种属性。 3、在查找表中插入一个数据元素; 4、从查找表中刪去某个数据元素。 |
静态查找表
|
对查找表只作前两种操作
|
动态查找表
|
在查找过程中查找表元素集合动态改变
|
关键字
|
是数据元素(或记录)中某个数据项的值
|
主关键字
|
可以唯一的地标识一个记录
|
次关键字
|
用以识别若干记录
|
查找
|
根据给定的某个值,在查找表中确定一个其关键字等于给定的记录或数据元素。若表中存在这样的一个记录,则称
查找是成功的
,此时查找的结果为给出整个记录的信息,或指示该记录在查找表中的位置;若表中不存在关键字等于给定值的记录,则称
查找不成功
。
|
典型的关键字类型说明:
|
typedef float KeyType;//实型 typedef int KeyType;//整型 typedef char *KeyType;//字符串型 |
数据元素类型定义为:
|
typedef struct{ KeyType key; // 关键字域 ... }ElemType; |
对两个关键字的比较约定为如下的宏定义:
|
对数值型关键字
#define EQ(a,b) ((a)==(b)) #define LT(a,b) ((a)<(b)) #define LQ(a,b) ((a)<=(b))
对字符串型关键字 #define EQ(a,b) (!strcmp((a),(b))) #define LT(a,b) (strcmp((a),(b))<0) #define LQ(a,b) (strcmp((a),(b))<=0) |
ADT StaticSearchTable{
数据对象D:D是具有相同特性的数据元素的集合。各个数据元素均含有类型相同,可唯一标识数据元素的关键字。
数据关系R:数据元素同属一个集合。
基本操作P:
Create(&ST,n);
操作结果:构造一个含n个数据元素的静态查找表ST。
Destroy(&ST);
初始条件:静态查找表ST存在。
操作结果:销毁表ST。
Search(ST,key);
初始条件:静态查找表ST存在,key为和关键字类型相同的给定值。
操作结果:若ST中在在其关键字等于key的数据元素,则函数值为该元素的值或在表中的位置,否则为“空”。
Traverse(ST,Visit());
初始条件:静态查找表ST存在,Visit是对元素操作的应用函数。
操作结果:按某种次序对ST的每个元素调用函数visit()一次且仅一次。一旦visit()失败,则操作失败。
}ADT StaticSearchTable
|
|
其中:Pi为查找表中第i个记录的概率,且;
Ci为找到表中其关键字与给定值相等的第i个记录时,和给定值已进行过比较的关键字个数。
|
|
等概率条件下有:
|
假设查找成功与不成功的概率相同:
|
|
a
|
b
|
c
|
d
|
e
|
f
|
g
|
h
|
i
|
j
|
k
|
l
|
m
|
n
|
o
|
p
|
q
|
r
|
s
|
t
|
u
|
v
|
w
|
x
|
y
|
z
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
13
|
14
|
15
|
16
|
17
|
18
|
19
|
20
|
21
|
22
|
23
|
24
|
25
|
26
|
|
刘丽
|
刘宏英
|
吴军
|
吴小艳
|
李秋梅
|
陈伟
|
...
|
姓名中各字拼音首字母
|
ll
|
lhy
|
wj
|
wxy
|
lqm
|
cw
|
...
|
用所有首字母编号值相加求和
|
24
|
46
|
33
|
72
|
42
|
26
|
...
|
最小值可能为3 最大值可能为78 可放75个学生
|
|
|
成绩一
|
成绩二...
|
3
|
...
|
|
|
...
|
...
|
|
|
24
|
刘丽
|
82
|
95
|
25
|
...
|
|
|
26
|
陈伟
|
|
|
...
|
...
|
|
|
33
|
吴军
|
|
|
...
|
...
|
|
|
42
|
李秋梅
|
|
|
...
|
...
|
|
|
46
|
刘宏英
|
|
|
...
|
...
|
|
|
72
|
吴小艳
|
|
|
...
|
...
|
|
|
78
|
...
|
|
|
地址
|
01
|
02
|
...
|
25
|
26
|
27
|
...
|
100
|
年龄
|
1
|
2
|
...
|
25
|
26
|
27
|
...
|
...
|
人数
|
3000
|
2000
|
...
|
1050
|
...
|
...
|
...
|
...
|
...
|
|
|
|
|
|
|
|
|
|
5864
|
|
5864
|
|
4220
|
|
0224
|
+)
|
04
|
+)
|
04
|
|
-----------
|
|
-----------
|
|
10088
|
|
6092
|
|
H(key)=0088
|
|
H(key)=6092
|
|
|
|
|
|
(a)移位叠加
|
|
(b)间界叠加
|
|
|
成绩一
|
成绩二...
|
3
|
...
|
|
|
...
|
...
|
|
|
24
|
刘丽
|
82
|
95
|
25
|
...
|
|
|
26
|
陈伟
|
|
|
...
|
...
|
|
|
33
|
吴军
|
|
|
...
|
...
|
|
|
42
|
李秋梅
|
|
|
...
|
...
|
|
|
46
|
刘宏英
|
|
|
...
|
...
|
|
|
72
|
吴小艳
|
|
|
...
|
...
|
|
|
78
|
...
|
|
|
0
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
|
|
|
|
|
60
|
17
|
29
|
|
|
|
0
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
|
|
|
|
|
60
|
17
|
29
|
38
|
|
|
0
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
|
|
|
|
|
60
|
17
|
29
|
|
|
|
0
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
|
|
|
38
|
|
60
|
17
|
29
|
|
|
|
姓名
|
年龄
|
体重
|
1李由
|
57
|
62
|
2王天
|
54
|
76
|
3七大
|
24
|
75
|
4张强
|
24
|
72
|
5陈华
|
24
|
53
|
姓名
|
年龄
|
体重
|
3七大
|
24
|
75
|
4张强
|
24
|
72
|
5陈华
|
24
|
53
|
2王天
|
54
|
76
|
1李由
|
57
|
62
|
姓名
|
年龄
|
体重
|
4张强
|
24
|
72
|
3七大
|
24
|
75
|
5陈华
|
24
|
53
|
2王天
|
54
|
76
|
1李由
|
57
|
62
|
38
|
49
|
65
|
97
|
76
|
13
|
27
|
49
|
...
|
|
38
|
49
|
65
|
76
|
97
|
13
|
27
|
49
|
...
|
|
13
|
38
|
49
|
65
|
76
|
97
|
27
|
49
|
...
|
|
13
|
27
|
38
|
49
|
65
|
76
|
97
|
49
|
...
|
|
13
|
27
|
38
|
49
|
49
|
65
|
76
|
97
|
...
|
|
49
|
38
|
65
|
97
|
78
|
13
|
27
|
49
|
...
|
|
i=1
|
49
|
|
|
|
|
|
|
|
|
first
|
|
|
|
|
|
|
|
i=2
|
49
|
|
|
|
|
|
|
38
|
|
final
|
|
|
|
|
|
|
first
|
i=3
|
49
|
65
|
|
|
|
|
|
38
|
|
|
final
|
|
|
|
|
|
first
|
i=4
|
49
|
65
|
97
|
|
|
|
|
38
|
|
|
|
final
|
|
|
|
|
first
|
i=5
|
49
|
65
|
76
|
97
|
|
|
|
38
|
|
|
|
|
final
|
|
|
|
first
|
i=6
|
49
|
65
|
76
|
97
|
|
|
13
|
38
|
|
|
|
|
final
|
|
|
first
|
|
i=7
|
49
|
65
|
76
|
97
|
|
13
|
27
|
38
|
|
|
|
|
final
|
|
first
|
|
|
i=8
|
49
|
49
|
65
|
76
|
97
|
13
|
27
|
38
|
|
|
|
|
|
final
|
first
|
|
|
49
|
38
|
38
|
38
|
38
|
13
|
13
|
38
|
49
|
49
|
49
|
13
|
27
|
27
|
65
|
65
|
65
|
13
|
27
|
38
|
38
|
97
|
76
|
13
|
27
|
49
|
49
|
|
76
|
13
|
27
|
49
|
49
|
|
|
13
|
27
|
49
|
65
|
|
|
|
27
|
49
|
78
|
|
|
|
|
49
|
97
|
|
|
|
|
|
初始
|
第一趟
|
第二趟
|
第三趟
|
第四趟
|
第五趟
|
第六趟
|
初始关键字
|
49
|
38
|
65
|
97
|
76
|
13
|
27
|
49
|
|
i
|
|
|
|
|
|
j
|
j
|
1次交换之后
|
27
|
38
|
65
|
97
|
76
|
13
|
|
49
|
|
i
|
|
i
|
|
|
|
j
|
|
2次交换之后
|
27
|
38
|
|
97
|
76
|
13
|
65
|
49
|
|
|
|
i
|
|
|
j
|
j
|
|
3次交换之后
|
27
|
38
|
13
|
97
|
76
|
|
65
|
49
|
|
|
|
i
|
i
|
|
j
|
|
|
4次交换之后
|
27
|
38
|
13
|
|
76
|
97
|
65
|
49
|
|
|
|
|
ij
|
|
j
|
|
|
完成一趟排序
|
27
|
38
|
13
|
49
|
76
|
97
|
65
|
49
|
|
|
|
|
|
|
|
|
|
初始状态
|
49
|
38
|
65
|
97
|
76
|
13
|
27
|
49
|
一次划分
|
27
|
38
|
13
|
49
|
76
|
97
|
65
|
49
|
分别进行
|
13
|
27
|
38
|