数据结构查找 C++
一.查找的基本概念
被查找对象是由一组元素组成的表或文件,每个元素由若干个数据项组成,并假设每个元素都有一个能唯一标识该元素的关键字。
- 若在查找的同时对表做了修改运算(例如插入和删除),则相应的表称为动态查找表,否则为静态查找表。
- 若整个查找过程都在内存中进行,则称之为内查找;若查找过程中需要访问外存,则称之为外查找。
- 平均查找长度(Average Search Length,ASL)的定义如下:
∑ i = 1 n p i c i \sum_{i=1}^n{p_ic_i} \quad i=1∑npici
其中,n是查找表中元素的个数;pi是查找第i个元素的概率,除特别指出外,均认为每个元素的查找概率相等,即pi=1/n(1≤i≤n);ci是找到第i个元素所需要进行的关键字比较次数。平均查找长度分为成功查找情况下和不成功查找情况下的平均查找长度两种。前者指在表中找到指定关键字的元素平均所需关键字比较的次数,后者指在表中找不到指定关键字的元素平均所需关键字比较次数。
二.线性表的查找
建立线性表查找的类
#include <iostream>
using namespace std;
#define MAXSIZE 10
class SqListSearch{
public:
SqListSearch();
~SqListSearch();
int binSearchRe(int low,int high,int k);
int binSearch(int k);
int seqSearch(int k);
private:
int* R;
int length;
};
SqListSearch::SqListSearch(){
R = new int[MAXSIZE]{1,2,3,4,5,6,7,8,9,10};
length = 10;
}
SqListSearch::~SqListSearch(){
delete [] R;
}
①顺序查找
int SqListSearch::seqSearch(int k){
int i=0;
while(i<length && R[i]!=k){
i++;
}
if(i>=length){
return 0;
}else{
return i+1;
}
}
②折半查找
- 递归查找
int SqListSearch::binSearchRe(int low,int high,int k){
int mid;
if(low<=high){
mid = (low+high)/2;
if(R[mid]==k){
return mid+1;
}
if(R[mid]>k){
return binSearchRe(low,mid-1,k);
}else{
return binSearchRe(mid+1,high,k);
}
}else{
return -1;
}
}
- 非递归查找
int SqListSearch::binSearch(int k){
int low=0,high=length-1,mid;
while(low<=high){
mid = (low+high)/2;
if(R[mid]==k){
return mid+1;
}
if(R[mid]>k){
high = mid-1;
}
else{
low = mid+1;
}
}
return -1;
}
main函数
int main(){
SqListSearch s;
int res = s.binSearchRe(0,9,9);
cout << "递归结果为:" << res << endl;
res = s.binSearch(9);
cout << "非递归结果为:" << res << endl;
return 0;
}
三.树表的查找
二叉排序树(简称BST)又称二叉查找(搜索)树,其定义为,二叉排序树或者空树,或者满足以下性质的二叉树:
- 若它的左子树非空,则左子树上所有元素的值均小于根元素的值
- 若它的右子树非空,则右子树上所有元素的值均大于根元素的值
- 左、右子树本身又各是一棵二叉排序树
建立二叉排序树的类
#include <iostream>
using namespace std;
#define MAXSIZE 100
class Node{
public:
int key;
char data;
Node *lChild;
Node *rChild;
};
class BSTree{
public:
BSTree();
~BSTree();
bool createBSTree(int a[],int n);
bool insertBSTree(int k);
bool searchBSTree(int k);
void dispBSTree();
private:
Node *r;
void destroyBSTree(Node *n);
Node *findNode1(Node *n,char e);
bool insertBSTree1(Node *&p,int k);
bool searchBSTree1(Node *n,int k);
void dispNode(Node *n);
};
BSTree::BSTree(){
r = NULL;
}
BSTree::~BSTree(){
destroyBSTree(r);
}
创建和销毁二叉排序树
void BSTree::destroyBSTree(Node *n){
if(n!=NULL){
destroyBSTree(n->lChild);
destroyBSTree(n->rChild);
delete n;
}
}
bool BSTree::createBSTree(int a[],int n){
int i=0;
while(i<n){
if(insertBSTree1(r,a[i])){
i++;
}else{
return false;
}
}
return true;
}
插入元素到二叉排序树
bool BSTree::insertBSTree1(Node *&p,int k){
if(p==NULL){
p = new Node();
p->key=k;
p->lChild=p->rChild=NULL;
return true;
}else if(k==p->key){
return false;
}else if(k<p->key){
return insertBSTree1(p->lChild,k);
}else{
return insertBSTree1(p->rChild,k);
}
}
查找二叉排序树的元素
bool BSTree::searchBSTree(int k){
return searchBSTree1(r,k);
}
bool BSTree::searchBSTree1(Node *n,int k){
if(n==NULL){
return false;
}
if(n->key==k){
return true;
}
if(k<n->key){
return searchBSTree1(n->lChild,k);
}else{
return searchBSTree1(n->rChild,k);
}
}
输出二叉排序树
void BSTree::dispBSTree(){
dispNode(this->r);
}
void BSTree::dispNode(Node *n){
if(n!=NULL){
cout << n->key;
if(n->lChild!=NULL || n->rChild!=NULL){
cout << "(";
dispNode(n->lChild);
if(n->rChild!=NULL){
cout << ",";
}
dispNode(n->rChild);
cout << ")";
}
}
}
main函数
int main(){
int num[]={4,9,0,1,8,6,3,5,2,7};
BSTree t;
t.createBSTree(num,10);
t.dispBSTree();
cout << endl;
bool b = t.searchBSTree(6);
if(b){
cout << "查找成功" << endl;
}else{
cout << "查找失败" << endl;
}
return 0;
}
四.哈希表的查找
哈希表存储的基本思路是,设要存储的对象个数为n,设置一个长度为m(m≥n)的连续内存单元,以每个对象的关键字ki(0≤i≤n-1)为自变量,通过一个被称为哈希函数h(ki),把ki映射为内存单元的地址(或称下标)h(ki),并把该对象存储在这个内存单元中。h(ki)也称为哈希地址(又称散列地址)。通常把如此构造的线性表存储结构称为哈希表。
-
哈希函数的构造方法
①直接定址法:h(ki) = k + c(常量)
②除留余数法:h(ki) = k mod p(mod为求余运算,p≤m)
③数字分析法 -
哈希冲突的解决方法
当发生哈希冲突时,即ki≠kj(i≠j),而h(ki)=h(kj)时,通过哈希冲突函数(设为h(kl),这里l=1,2,3,…,m-1)产生一个新的哈希地址,使h(ki)≠h(kj)
①开放地址法
②拉链法
建立哈希表的类(除留余数法+开放地址法)
# define NULLKEY -1
# define DELKEY -2
#include <iostream>
using namespace std;
class HashTable{
public:
int key;
int count;
};
class HashClass{
public:
HashClass();
HashClass(int len);
~HashClass();
void hashDisp();
void hashSearch(int k);
bool hashDelete(int k);
void hashInsert(int k);
void hashCreate(int keys[]);
private:
HashTable *ht;
int length;
int p;
};
HashClass::HashClass(int len){
ht = new HashTable[len];
length = len;
while(len>0){
if(len%2==1){
p = len;
break;
}
len--;
}
}
HashClass::~HashClass(){
delete [] ht;
}
创建哈希表
void HashClass::hashCreate(int keys[]){
for(int i=0;i<length;i++){
ht[i].key = NULLKEY;
ht[i].count = 0;
}
for(int j=0;j<length;j++){
hashInsert(keys[j]);
}
}
void HashClass::hashInsert(int k){
int i,adr;
adr = k%p;
if(ht[adr].key==NULLKEY||ht[adr].key==DELKEY){
ht[adr].key = k;
ht[adr].count = 1;
}else{
i=1;
do{
adr = (adr+1)%length;
i++;
}while(ht[adr].key!=NULLKEY&&ht[adr].key!=DELKEY);
ht[adr].key = k;
ht[adr].count = 1;
}
}
删除哈希表中的元素
bool HashClass::hashDelete(int k){
int adr;
adr = k%p;
while(ht[adr].key!=NULLKEY&&ht[adr].key!=DELKEY){
adr = (adr+1)%length;
if(ht[adr].key==k){
ht[adr].key=DELKEY;
return true;
}else{
return false;
}
}
}
查找哈希表中的元素
void HashClass::hashSearch(int k){
int i=1,adr;
adr=k%p;
while(ht[adr].key!=NULLKEY&&ht[adr].key!=k){
i++;
adr = (adr+1)%length;
}
if(ht[adr].key==k){
cout << "查找成功" << endl;
}else{
cout << "查找失败" << endl;
}
}
输出哈希表中的元素
void HashClass::hashDisp(){
for(int i=0;i<length;i++){
if(ht[i].key>=16&&ht[i].key<=90){
int k=ht[i].key;
cout << k << " ";
}else{
cout << "∧" << " ";
}
}
cout << endl;
}
main函数
int main(){
HashClass hc(13);
int num[] = {16,74,60,43,54,90,46,31,29,88,77};
hc.hashCreate(num);
hc.hashDisp();
cout << "查找关键字为29的元素结果:";
hc.hashSearch(29);
cout << "删除关键字为77的元素后:";
hc.hashDelete(77);
hc.hashDisp();
cout << "插入关键字为77的元素后:";
hc.hashInsert(77);
hc.hashDisp();
return 0;
}

556

被折叠的 条评论
为什么被折叠?



