我原本想說的是Unix系統C標準庫所提供的一些算法和數據結構API,但畢竟帶有iOS標題可能更加吸引眼球一些。其實我說的也沒有錯,由於iOS畢竟是從Unix衍生出來的系統,因此說標題所述也算是正確的。下面將要介紹的幾類API,有些能夠在POSIX平臺中支持,有些則只能在FreeBSD中支持,有些則只有在iOS系統中單獨支持。算法
iOS系統中的C標準庫中主要提供了線性查找、二分查找、雙向鏈表、快速排序、堆排序、歸併排序、並行排序、基數排序、二叉排序樹、哈希表、KV數據庫、位串、內存池、cache等衆多的API。這些API基本覆蓋了在應用中的常見數據結構和算法的需求。數據庫
那既然Foundation和CoreFoundation庫中都提供了衆多的基於OC語言的算法和數據結構爲何還要使用這些函數呢?緣由就是性能和兼容性。數組
功能:遍歷數組,查找知足條件的記錄。bash
頭文件:#include <search.h>數據結構
平臺:POSIX數據結構和算法
函數簽名:函數
//查找
void *lfind(const void *key, const void *base, size_t *nelp, size_t width, int (*compar)(const void *, const void *));
//查找並追加
void *lsearch(const void *key, void *base, size_t *nelp, size_t width, int (*compar)(const void *, const void *));
複製代碼
參數:oop
key: [in] 要查找的元素。性能
base:[in] 數組元素的首地址。ui
nelp: [in/out] 數組的元素個數指針。
width: [in] 數組中每一個元素的尺寸。
compar: [in] 函數比較器,查找時會對數組中的每一個元素進行遍歷並和要查找的元素調用函數比較器來判斷是否匹配成功。函數比較器的格式以下:
/*
@key: 是要查找的元素,也是上面lfind和lsearch中傳入的第一個參數key。
@element: 元素在數組中的地址,這裏須要注意的是這個參數不是元素自己,而是元素所在的數組中的偏移地址。
@return: 若是比較結果相等則返回0,不然返回非0
*/
int compar(const void *key, const void *element);
複製代碼
return:[out] 若是數組中找到了對應的元素,則返回元素在數組中的地址,若是沒有找到則lfind返回NULL。而lsearch則會將要查找的元素追加到數組後面,並返回元素在數組中的地址,同時更新nelp的值。
描述:
系統提供的lfind和lsearch函數都是用於線性查找,可是兩者的區別是:
lsearch也有可能在查找添加失敗時返回NULL。
示例代碼:
typedef struct student
{
int age;
char *name;
} student_t;
//注意這裏的key的類型能夠不和數組元素類型相同,同時第二個參數是元素在數組中的指針而不是元素自己。
int lfindcompar(const char *key, const student_t *pstudent)
{
return strcmp(key, pstudent->name);
}
//注意這裏的key的類型必需要和數組元素類型相同,同時第二個參數是元素在數組中的指針而不是元素自己。
int lsearchcompar(const student_t *key, const student_t *pstudent)
{
return strcmp(key->name, pstudent->name);
}
void main()
{
student_t students[10] = {{10, "Bob"}, {20, "Alex"}, {15, "Lucy"}, {19, "Ada"}, {25, "Max"}};
size_t count = 5; // 實際的元素個數爲5
//lfind第一次查找沒有找到
student_t *pstudent = lfind("Lily", students, &count, sizeof(student_t), &lfindcompar);
NSAssert(pstudent == NULL, @"oops"); //沒有找到。
student_t newstudent = {20, "Lily"};
//lsearch中的key的類型必需要和數組元素類型保持一致,若是沒有找到就會添加到數組尾部,而且數量參數count會加1
pstudent = lsearch(&newstudent, students, &count, sizeof(student_t), &lsearchcompar);
NSAssert(pstudent != NULL && count == 6, @"oops");
//再次經過lfind就查找成功了。
pstudent = lfind("Lily", students, &count, sizeof(student_t), &lfindcompar);
NSAssert(pstudent != NULL, @"oops");
}
複製代碼
功能:對有序數組進行二分查找,並查找知足條件的記錄,二分查找法的時間複雜度爲logN。
頭文件:#include <stdlib.h>
平臺:POSIX
函數簽名:
void *bsearch(const void *key, const void *base, size_t nel, size_t width, int (*compar) (const void *, const void *));
//bsearch_b並非POSIX標準中的函數,而是iOS對二分查找的block形式的擴展
void *bsearch_b(const void *key, const void *base, size_t nel, size_t width, int (^compar) (const void *, const void *));
複製代碼
參數:
key: [in] 要查找的元素。
base:[in] 數組元素的首地址。
nel: [in] 數組的元素個數。
width: [in] 數組中每一個元素的尺寸。
compar: [in] 函數比較器,查找時會對數組的某些元素和要查找的元素調用函數比較器來判斷是否匹配成功。函數比較器的格式以下
/*
@key: 是要查找的元素,也是上面bsearch和bsearch_b中傳入的第一個參數key。
@element: 元素在數組中的地址,這裏須要注意的是這個參數不是元素自己,而是元素所在的數組中的偏移地址。
@return : 若是比較結果相等則返回0, 若是key小於element則返回小於0,若是key大於element則返回大於0
*/
int compar(const void *key, const void *element);
複製代碼
return:若是找到則返回元素在數組中的指針,若是沒有找到則返回NULL。
描述:
函數要求數組必須是有序的,至因而升序仍是降序則跟函數比較器的返回是相關的。默認的狀況是按升序進行二分查找的。bsearch_b和bsearch的區別是前者是block的形式的比較器,然後者則是函數形式的比較器,block形式的比較器功能更增強大一些。
示例代碼:
int bsearchcompar(const int *key, const student_t *pstudent)
{
return *key - pstudent->age;
}
void main()
{
student_t students[5] = {{10, "Bob"}, {20, "Alex"}, {30, "Lucy"}, {40, "Ada"}, {50, "Max"}};
int age = 30; //查找的關鍵字
student_t *pstudent = bsearch(&age, students, sizeof(students)/sizeof(student_t), sizeof(student_t), &bsearchcompar);
NSAssert(pstudent != NULL && pstudent->age == 30);
}
複製代碼