查找-基于线性表


1、顺序查找


对于一个无序的,即关键字没有排序的线性表来说,用所给的关键字与线性表中的所有记录逐个进行比较,直到成功或者失败。


平均查找长度:ASL=(n+1)/2


I、最不频繁使用法(LFU):也叫作计数法,为线性表中的每条记录保存一个访问计数,并按照访问频率从高到低进行排序,而且一直按照这个顺序维护记录。这样,每当访问一条记录时,如果该记录的访问数已经大于它前面记录的访问数,这条记录就会在线性表中向前移动。很明显,这种方法为了保护访问计数需要占用空间,另外,该方法对记录访问频率随时间而改变的反应也不好。在频率计数中,一旦一条记录被访问了很多次,不管将来的访问次数怎样。它都一直位于线性表的前面。


II、最近最少使用法(LUR):也叫作移至前端法,如果找到一条记录就把他移至线性表的最前面,而把其他记录后退一个位置。显然,这种方式使用链表来存储比较好实现。同时,该方法对访问频率的局部变化反应很好,这是因为如果一条记录在一段时间内被频繁访问,在短时间它就会靠近线性表的前边。现在,搜狗拼音、紫光等输入法,使用的都是这种方法,把当前常用的字和词都移至前端,有效的提高了输入汉字的速度。


III、转置(transpose)方法:也叫作调换方法,把找到的记录与它表中的前一条记录交换位置。这种方法无论是基于链表存储还是数组存储,都是很好的方法。随着时间的推移,最常使用的记录将移动到线性表的前面。曾经被频繁访问但以后不会再使用的记录将会慢慢的落到后面。该方法在大部分情况下对访问频率的变化有很好的反应。但是,也会出现一些极端的情况。例如,首先访问线性表的最后一条记录I,然后就把这条记录与倒数第二条记录J交换位置,使得J称为最后一条记录。如果接下来访问的依然是最后一条记录J,那么就会和倒数第二条记录I交换位置。如果访问序列恰好就这样在I和J之间不断交替,将总是查找该表的最后位置,而这两条记录始终不能往前移动。不过,这种情况在实际情况中很少出现。


2、折半查找(二分查找)


对于任何一个线性表,若其中的所有数据元素都按照关键字的大小呈递减或递增排列,则称为有序表。

折半查找首先要求查找表满足:查找表采用顺序存储(数组)结构,并且按关键字大小有序排列。


基本查找过程:每次将待查范围中间位置上的数据元素的关键字与给定值K比较,如果相等就查找成功;否则利用该位置将整个表划分成前、后两个子表,如果中间位置记录的关键字大于待查关键字,则继续在前半部分子表进行查找,否则就在后半部分子表进行查找,重复此过程,直到“查找成功”或“查找不成功”。


折半查找是典型的分治类算法,所以算法也可以利用递归来实现。


平均查找长度:ASL=((n+1)/n)*log2(n+1)-1,当n>50时,ASL约等于log2(n+1)-1


折半查找的有点2在于关键字的比较次数比较少,查找速度快,平均性能较好,但缺点是要求待查表必须为有序表,而且要基于顺序结构存储,这对于插入和删除操作来说是比较困难的。因此,折半查找适合于一经建立就很少改动,而且有需要经常查找的有序查找表。


3、索引查找(分块查找)


如果线性表既希望有较快的查找速度,有需要动态变化,则可以采用索引查找。索引查找又称为分块查找,它是一种性能介于顺序查找和折半查找之间的查找办法。


基本思想:1、把线性表分成若干块,每块包含若干记录,在每一块中记录的存放是任意的,但块与块之间必须是有序的(分块有序)。2、建立一个索引表,把每块中的最大关键字值以及每块的第一个记录在表中的位置和最后一个记录在表中的位置存放在索引项中。所以,索引表是一个有序表。


查找时,首先用待查找的关键字在索引表中查找,确定具有该关键字的结点应该在哪一个分块中,在索引中查找的方法可以采用顺序查找或是折半查找,然后再到相应的分块中顺序查找,即可得到查找结果。


第一个阶段以折半查找ASL约为log2(n/i+1)+(i+1)/2;若第一阶段以顺序查找ASL=(n+i^2)/(2*i)+1


索引查找的优点在于在线性表中插入一个或删除一个结点时,只要找到该结点应属于的块,然后在块内进行插入或删除运算。由于块内结点的存放是任意的,因此插入或删除比较容易,不需要移动大量的结点。插入可直接在块尾进行;如果待删的记录不是块中最后一个记录时,可将本块内最后一个记录移入被删记录的位置。因此,在某些情况下索引查找是比较容易实现的。


### C语言实现基于线性表的图书信息系统 #### 1. 结构体定义 为了构建一个简单的图书管理系统,首先需要定义两个结构体:`Book` 和 `BookList`。前者用于描述单本书的信息,后者则用来表示整个图书列表。 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> // 定义图书信息结构体 typedef struct { int id; // 图书ID char title[100]; // 图书标题 char author[100]; // 作者姓名 int quantity; // 数量 } Book; // 定义线性表结构体来存储图书信息 typedef struct { Book* books; // 存储图书的数组指针 int length; // 当前线性表中的元素个数 int capacity; // 线性表的最大容量 } BookList; ``` #### 2. 初始化函数 创建一个新的空书籍列表时,初始化其内部成员变量是非常重要的一步。这可以通过下面这个函数完成: ```c void init_book_list(BookList* list, int initial_capacity) { list->books = (Book*)malloc(initial_capacity * sizeof(Book)); list->length = 0; list->capacity = initial_capacity; } ``` #### 3. 插入新书功能 当向系统中添加一本新的书籍记录时,如果当前已满,则需先扩大容器大小再执行插入操作。 ```c int add_book(BookList* list, const Book* book) { if (list->length >= list->capacity) { // 扩展容量到原来的两倍 list->capacity *= 2; list->books = realloc(list->books, list->capacity * sizeof(Book)); if (!list->books) return -1; // 内存不足返回错误码 } memcpy(&list->books[list->length++], book, sizeof(Book)); return 0; } ``` #### 4. 查找特定编号的书籍 对于给定的一个唯一标识符(即id),可以在现有集合里寻找匹配项并打印出来。 ```c void find_by_id(const BookList* list, int target_id) { for(int i=0;i<list->length;++i){ if(target_id==list->books[i].id){ printf("Found:\n"); printf("Title:%s\n",list->books[i].title); printf("Author:%s\n",list->books[i].author); printf("Quantity:%d\n",list->books[i].quantity); break ; } } } ``` #### 5. 删除指定位置上的书籍条目 允许用户移除不再需要保存的数据行;这里采用覆盖的方式来进行实际意义上的删除动作。 ```c void remove_at_index(BookList* list, unsigned index) { if(index>=list->length || !list->length)return ; memmove(&list->books[index],&list->books[index+1], (--list->length-index)*sizeof(Book)); } ``` 以上就是利用C语言和顺序线性表原理搭建起来的基础版图书馆管理程序框架[^1]。当然,在真实项目开发过程中还需要考虑更多细节问题以及异常情况处理机制等内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值