41、UNIX编程中的常用算法与函数详解

UNIX编程中的常用算法与函数详解

在UNIX编程中,有许多常用的算法和函数可以帮助我们更高效地处理数据和完成各种任务。下面将详细介绍一些常见的算法和函数,包括线性搜索、二分搜索、哈希表、二叉树、队列操作、排序、环境变量处理以及密码加密等。

1. 线性搜索示例

线性搜索是一种简单的搜索方法,通过逐个比较元素来查找目标。以下是一个简单的线性搜索示例:

int compare(const void *a, const void *b) 
{ 
    return(strcmp((char *) a, (char *) b)); 
} 

在这个示例中,我们可以输入10个字符串,然后进行搜索操作。例如:

Enter 10 strings, not all unique.
1> abcdef
2> ghijkl
3> mnopqr
4> stuvwx
5> yz
6> abcdef
7> ghijkl
8> mnopqr
9> stuvwx
10> yz
Contents of the table:
        abcdef
        ghijkl
        mnopqr
        stuvwx
        yz
Search for: abc
String not found.
Search for: abcdef
Found at location 1.
Search for: ghijkl
Found at location 2.
Search for: mn
String not found.
Search for: yz
Found at location 5.
2. 二分搜索

二分搜索是一种高效的搜索方法,适用于大型有序表。其基本思想是每次将搜索范围缩小一半,直到找到目标元素或确定目标元素不存在。二分搜索的时间复杂度为 $O(log n)$。

二分搜索通过 bsearch 函数实现:

#include <stdlib.h>

void *bsearch(const void *key, const void *base, size_t nel,
        size_t size, int (*compar)(const void *, const void *));
  • key :要查找的元素。
  • base :指向要搜索的表的起始位置。
  • nel :表中元素的数量。
  • size :每个元素的大小(以字节为单位)。
  • compar :指向一个比较函数的指针,用于比较两个元素。

以下是一个使用 bsearch 函数搜索系统拼写字典的示例:

#include <search.h> 
#include <string.h> 
#include <stdio.h> 

#define TABLESIZE   32768       /* max. size of the table       */ 
#define ELEMENTSIZE 32          /* max. size of a table element */ 

int compare(const void *, const void *); 

int 
main(void) 
{ 
    char *p; 
    FILE *fp; 
    size_t nel; 
    char line[ELEMENTSIZE]; 
    char table[TABLESIZE][ELEMENTSIZE]; 

    /* 
     * Open the file. 
     */ 
    if ((fp = fopen("/usr/dict/words", "r")) == NULL) { 
        perror("/usr/dict/words"); 
        exit(1); 
    } 

    printf("Reading the table... "); 
    fflush(stdout); 

    /* 
     * Read in the file. 
     */ 
    for (nel = 0; nel < TABLESIZE; nel++) { 
        /* 
         * Read a line. 
         */ 
        if (fgets(table[nel], ELEMENTSIZE, fp) == NULL) 
            break; 

        /* 
         * Strip the newline. 
         */ 
        table[nel][strlen(table[nel]) - 1] = '\0'; 
    } 

    printf("done.\n"); 
    fclose(fp); 

    /* 
     * Let the user search for things. 
     */ 
    for (;;) { 
        /* 
         * Prompt for a search string. 
         */ 
        printf("\nSearch for: "); 

        /* 
         * Read the search string. 
         */ 
        if (fgets(line, sizeof(line), stdin) == NULL) { 
            putchar('\n'); 
            exit(0); 
        } 

        /* 
         * Strip the newline. 
         */ 
        line[strlen(line) - 1] = '\0'; 

        /* 
         * Do a binary search for the string. 
         */ 
        p = (char *) bsearch(line, table, nel, ELEMENTSIZE, compare); 

        /* 
         * Print the search results. 
         */ 
        if (p == NULL) { 
            printf("String not found.\n"); 
        } 
        else { 
            printf("Found at location %d.\n", 
                   ((int) p - (int) table) / ELEMENTSIZE); 
        } 
    } 
} 

/* 
 * compare - compare two strings, return 0 if equal, non-zero if not. 
 */ 
int 
compare(const void *a, const void *b) 
{ 
    return(strcasecmp((char *) a, (char *) b)); 
} 

该程序的执行流程如下:
1. 打开系统拼写字典文件 /usr/dict/words
2. 读取文件内容到数组中,并去除每行的换行符。
3. 提示用户输入要搜索的字符串。
4. 使用 bsearch 函数进行二分搜索。
5. 输出搜索结果。

3. 哈希表

哈希表是一种常用的数据结构,用于管理符号表等。它通过哈希函数将键映射到一个桶中,从而实现快速查找。哈希表的优点是插入和查找操作的平均时间复杂度为 $O(1)$,但需要合理估计表的大小,否则可能会导致效率低下。

哈希表通过 hsearch hcreate hdestroy 函数实现:

#include <search.h> 

typedef struct { 
    char    *key; 
    char    *data; 
} ENTRY; 

typedef enum { FIND, ENTER } ACTION; 

ENTRY *hsearch(ENTRY item, ACTION action); 

int hcreate(size_t nel); 

void hdestroy(void); 
  • hcreate :创建一个哈希表, nel 是对表中最大条目数的估计。
  • hsearch :在哈希表中搜索或插入条目。
  • hdestroy :销毁哈希表。

以下是一个使用哈希表管理人员信息的示例:

#include <search.h> 
#include <string.h> 
#include <stdlib.h> 
#include <stdio.h> 

struct data { 
    int age; 
    int height; 
    int weight; 
}; 

int 
main(void) 
{ 
    char *p; 
    ENTRY item; 
    ENTRY *result; 
    struct data *d; 
    char buf[BUFSIZ]; 

    /* 
     * Create the hash table. 
     */ 
    hcreate(100); 

    printf("Enter Name/age/height/weight; terminate with blank line.\n\n"); 

    /* 
     * Read information until a blank line. 
     */ 
    while (fgets(buf, sizeof(buf), stdin) != NULL) { 
        /* 
         * Blank line, all done. 
         */ 
        if (*buf == '\n') 
            break; 

        /* 
         * Allocate a data structure (we should check for 
         * errors here). 
         */ 
        d = (struct data *) malloc(sizeof(struct data)); 
        item.data = (char *) d; 

        /* 
         * Split up the data (we should check for errors 
         * here). 
         */ 
        p = strtok(buf, "/"); 
        item.key = strdup(p); 

        p = strtok(NULL, "/"); 
        d->age = atoi(p); 

        p = strtok(NULL, "/"); 
        d->height = atoi(p); 

        p = strtok(NULL, "/"); 
        d->weight = atoi(p); 

        /* 
         * Add the item to the table. 
         */ 
        (void) hsearch(item, ENTER); 
    } 

    /* 
     * Let the user search for things. 
     */ 
    for (;;) { 
        /* 
         * Prompt for a search string. 
         */ 
        printf("\nSearch for: "); 

        /* 
         * Read the search string. 
         */ 
        if (fgets(buf, sizeof(buf), stdin) == NULL) { 
            putchar('\n'); 
            hdestroy(); 
            exit(0); 
        } 

        /* 
         * Strip the newline. 
         */ 
        buf[strlen(buf) - 1] = '\0'; 

        /* 
         * Look in the table for the item. 
         */ 
        item.key = buf; 
        result = hsearch(item, FIND); 

        /* 
         * Print the search results. 
         */ 
        if (result == NULL) { 
            printf("Entry not found.\n"); 
        } 
        else { 
            d = (struct data *) result->data; 
            printf("Name: %s\nAge: %d\nHeight: %d\nWeight: %d\n", 
                   result->key, d->age, d->height, d->weight); 
        } 
    } 
} 

该程序的执行流程如下:
1. 创建一个哈希表,估计最大条目数为100。
2. 提示用户输入人员信息,格式为 Name/age/height/weight ,以空行结束输入。
3. 将输入的信息存储到哈希表中。
4. 提示用户输入要搜索的姓名。
5. 使用 hsearch 函数进行搜索。
6. 输出搜索结果。

4. 二叉树

二叉树是一种高效的数据结构,用于维护有序列表。在二叉树中,每个节点的左子树中的所有节点都小于该节点,右子树中的所有节点都大于该节点。二叉树的搜索操作的平均时间复杂度为 $O(log n)$。

二叉树通过 tsearch tfind tdelete twalk 函数实现:

#include <search.h> 

typedef enum { preorder, postorder, endorder, leaf } VISIT; 

void *tsearch(const void *key, void **rootp, 
        int (*compar)(const void *, const void *)); 

void *tfind(const void *key, const void **rootp, 
        int (*compar)(const void *, const void *)); 

void *tdelete(const void *key, void **rootp, 
        int (*compar)(const void *, const void *)); 

void twalk(void *rootp, void(*action)(void **, VISIT, int)); 
  • tsearch :构建和搜索二叉树。
  • tfind :查找二叉树中的元素。
  • tdelete :从二叉树中删除元素。
  • twalk :遍历二叉树。

以下是一个使用二叉树存储字符串并按字母顺序输出的示例:

#include <search.h> 
#include <string.h> 
#include <stdlib.h> 
#include <stdio.h> 

struct node { 
    char    *string; 
    int     length; 
}; 

int     compareNode(const void *, const void *); 
void    printNode(void **, VISIT, int); 

int 
main(void) 
{ 
    void *root; 
    struct node *n; 
    char buf[BUFSIZ]; 

    root = NULL; 

    /* 
     * Read strings until end of file. 
     */ 
    while (fgets(buf, sizeof(buf), stdin) != NULL) { 
        /* 
         * Strip the newline. 
         */ 
        buf[strlen(buf) - 1] = '\0'; 

        /* 
         * Allocate a node structure. 
         */ 
        n = (struct node *) malloc(sizeof(struct node)); 

        if (n == NULL) { 
            fprintf(stderr, "out of memory.\n"); 
            exit(1); 
        } 

        /* 
         * Save the information in the node. 
         */ 
        n->string = strdup(buf); 
        n->length = strlen(buf); 

        /* 
         * Add the item to the tree. 
         */ 
        (void) tsearch((void *) n, &root, compareNode); 
    } 

    /* 
     * Print out the tree in alphabetical order. 
     */ 
    twalk(root, printNode); 

    exit(0); 
} 

/* 
 * compareNode - compare the strings in two nodes. 
 */ 
int 
compareNode(const void *a, const void *b) 
{ 
    struct node *aa, *bb; 

    aa = (struct node *) a; 
    bb = (struct node *) b; 

    return(strcmp(aa->string, bb->string)); 
} 

/* 
 * printNode - print a node - we only print if this is the postorder (inorder) 
 *             visit or a leaf; this results in alphabetical order. 
 */ 
void 
printNode(void **node, VISIT order, int level) 
{ 
    struct node *n; 

    n = *(struct node **) node; 

    if (order == postorder || order == leaf) 
        printf("level=%d, length=%d, string=%s\n", level, n->length, n->string); 
} 

该程序的执行流程如下:
1. 初始化二叉树的根节点为 NULL
2. 从标准输入读取字符串,直到文件结束。
3. 为每个字符串分配一个节点,并将其插入到二叉树中。
4. 使用 twalk 函数按字母顺序遍历二叉树并输出节点信息。

5. 队列操作

队列是一种先进先出(FIFO)的数据结构,可以通过双向链表实现。在UNIX编程中,提供了 insque remque 函数来操作队列:

#include <search.h> 

void insque(struct qelem *elem, struct qelem *pred); 
void remque(struct qelem *elem); 

struct qelem { 
    struct qelem    *q_forw; 
    struct qelem    *q_back; 
    char            *q_data; 
}; 
  • insque :将元素 elem 插入到队列中 pred 元素的后面。
  • remque :从队列中移除元素 elem

需要注意的是,HP - UX 10.x 不提供 struct qelem 数据类型, insque remque 的参数类型为 void *

6. 排序

在UNIX编程中, qsort 函数用于对数据进行原地排序,它实现了快速排序算法,平均时间复杂度为 $O(n log n)$。

#include <stdlib.h> 

void qsort(void *base, size_t nel, size_t width, 
        int (*compar)(const void *, const void *)); 
  • base :指向要排序的表的起始位置。
  • nel :表中元素的数量。
  • width :每个元素的大小(以字节为单位)。
  • compar :指向一个比较函数的指针,用于比较两个元素。

以下是一个使用 qsort 函数对数组进行排序的示例:

#include <stdlib.h> 

#define NELEM   10 

int compare(const void *, const void *); 

int 
main(void) 
{ 
    int i; 
    int array[NELEM]; 

    /* 
     * Fill the array with numbers. 
     */ 
    for (i = 0; i < NELEM; i++) 
        array[NELEM - i - 1] = (i * i) & 0xf; 

    /* 
     * Print it. 
     */ 
    printf("Before sorting:\n\t"); 

    for (i = 0; i < NELEM; i++) 
        printf("%d ", array[i]); 
    putchar('\n'); 

    /* 
     * Sort it. 
     */ 
    qsort(array, NELEM, sizeof(int), compare); 

    /* 
     * Print it again. 
     */ 
    printf("After sorting:\n\t"); 

    for (i = 0; i < NELEM; i++) 
        printf("%d ", array[i]); 
    putchar('\n'); 

    exit(0); 
} 

/* 
 * compare - compare two integers. 
 */ 
int 
compare(const void *a, const void *b) 
{ 
    int *aa, *bb; 

    aa = (int *) a; 
    bb = (int *) b; 

    return(*aa - *bb); 
} 

该程序的执行流程如下:
1. 初始化一个包含10个元素的数组。
2. 输出排序前的数组元素。
3. 使用 qsort 函数对数组进行排序。
4. 输出排序后的数组元素。

7. 环境变量

每个进程都有一组与之关联的环境变量,包括搜索路径、终端类型、用户登录名等。在UNIX编程中,可以通过以下函数来处理环境变量:
- getenv :获取指定环境变量的值。

#include <stdlib.h> 

char *getenv(char *name); 
  • putenv :设置新的环境变量。
#include <stdlib.h> 

int putenv(char *string); 

以下是一个打印环境变量的示例:

#include <stdio.h> 

int 
main(int argc, char **argv, char **envp) 
{ 
    while (*envp != NULL) 
        printf("%s\n", *envp++); 

    exit(0); 
} 

该程序会遍历环境变量数组并打印每个环境变量。

8. 密码加密

UNIX密码加密基于修改版的数据加密标准(DES)。当用户选择密码时, passwd 程序会随机选择两个字符作为盐(salt),然后将密码和盐传递给 crypt 函数进行加密:

#include <crypt.h> 

char *crypt(const char *key, const char *salt); 

密码加密的过程如下:
1. 从密码的每个字符中提取7位,形成56位的DES密钥。
2. 根据盐的值对DES算法中的一个内部表进行4096种不同的排列。
3. 对一个全零块执行25次DES算法。
4. 将加密结果转换为64字符的字母表(A - Z、a - z、0 - 9、 . / )。

加密后的字符串包含两个字符的盐和11个字符的加密结果,且加密过程是单向的,无法解密。

当程序提示用户输入密码时,通常会使用 getpass 函数。

综上所述,这些算法和函数在UNIX编程中非常实用,可以帮助我们更高效地处理各种任务。在实际应用中,需要根据具体需求选择合适的算法和函数。

UNIX编程中的常用算法与函数详解(续)

9. 函数总结与对比

为了更清晰地了解这些算法和函数的特点和适用场景,我们可以对它们进行一个总结和对比。以下是一个简单的表格:
| 数据结构/算法 | 函数 | 时间复杂度 | 适用场景 |
| — | — | — | — |
| 线性搜索 | compare | $O(n)$ | 小规模无序数据搜索 |
| 二分搜索 | bsearch | $O(log n)$ | 大规模有序数据搜索 |
| 哈希表 | hsearch hcreate hdestroy | 平均 $O(1)$ | 快速查找和插入操作,需合理估计表大小 |
| 二叉树 | tsearch tfind tdelete twalk | 平均 $O(log n)$ | 维护有序列表,需要频繁插入、删除和查找操作 |
| 队列 | insque remque | $O(1)$ | 先进先出的数据处理 |
| 排序 | qsort | $O(n log n)$ | 对数据进行原地排序 |
| 环境变量 | getenv putenv | - | 获取和设置进程的环境变量 |
| 密码加密 | crypt | - | 对用户密码进行加密处理 |

通过这个表格,我们可以根据具体的需求和数据特点,选择最合适的算法和函数。

10. 实际应用案例分析

下面我们来看一些实际应用案例,进一步说明这些算法和函数在实际编程中的使用。

10.1 文本搜索工具

假设我们要开发一个简单的文本搜索工具,用于在一个大文件中查找特定的字符串。我们可以使用二分搜索算法来提高搜索效率。以下是一个简化的实现思路:
1. 读取文件 :将文件内容读取到一个数组中,并对数组进行排序。
2. 用户输入 :提示用户输入要搜索的字符串。
3. 二分搜索 :使用 bsearch 函数在排序后的数组中进行搜索。
4. 输出结果 :根据搜索结果输出相应的信息。

以下是一个简单的代码示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LINES 1000
#define MAX_LENGTH 100

int compare(const void *a, const void *b) {
    return strcmp((const char *)a, (const char *)b);
}

int main() {
    FILE *fp;
    char lines[MAX_LINES][MAX_LENGTH];
    int line_count = 0;
    char search_str[MAX_LENGTH];

    // 打开文件
    fp = fopen("large_file.txt", "r");
    if (fp == NULL) {
        perror("Failed to open file");
        return 1;
    }

    // 读取文件内容
    while (fgets(lines[line_count], MAX_LENGTH, fp) != NULL && line_count < MAX_LINES) {
        lines[line_count][strcspn(lines[line_count], "\n")] = 0; // 去除换行符
        line_count++;
    }
    fclose(fp);

    // 对数组进行排序
    qsort(lines, line_count, sizeof(lines[0]), compare);

    // 提示用户输入搜索字符串
    printf("Enter the string to search: ");
    fgets(search_str, MAX_LENGTH, stdin);
    search_str[strcspn(search_str, "\n")] = 0; // 去除换行符

    // 二分搜索
    char *result = (char *)bsearch(search_str, lines, line_count, sizeof(lines[0]), compare);

    // 输出结果
    if (result != NULL) {
        printf("String found: %s\n", result);
    } else {
        printf("String not found.\n");
    }

    return 0;
}
10.2 人员信息管理系统

我们可以使用哈希表来实现一个简单的人员信息管理系统。该系统可以让用户输入人员信息,并进行查询操作。以下是一个简化的实现思路:
1. 创建哈希表 :使用 hcreate 函数创建一个哈希表。
2. 用户输入 :提示用户输入人员信息,格式为 Name/age/height/weight ,以空行结束输入。
3. 插入信息 :将用户输入的信息插入到哈希表中。
4. 查询信息 :提示用户输入要查询的姓名,使用 hsearch 函数进行查询。
5. 输出结果 :根据查询结果输出相应的信息。

以下是一个简单的代码示例:

#include <search.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

struct data {
    int age;
    int height;
    int weight;
};

int main() {
    char *p;
    ENTRY item;
    ENTRY *result;
    struct data *d;
    char buf[BUFSIZ];

    // 创建哈希表
    hcreate(100);

    printf("Enter Name/age/height/weight; terminate with blank line.\n\n");

    // 读取信息
    while (fgets(buf, sizeof(buf), stdin) != NULL) {
        if (*buf == '\n')
            break;

        d = (struct data *)malloc(sizeof(struct data));
        item.data = (char *)d;

        p = strtok(buf, "/");
        item.key = strdup(p);

        p = strtok(NULL, "/");
        d->age = atoi(p);

        p = strtok(NULL, "/");
        d->height = atoi(p);

        p = strtok(NULL, "/");
        d->weight = atoi(p);

        (void)hsearch(item, ENTER);
    }

    // 查询信息
    for (;;) {
        printf("\nSearch for: ");
        if (fgets(buf, sizeof(buf), stdin) == NULL) {
            putchar('\n');
            hdestroy();
            exit(0);
        }
        buf[strlen(buf) - 1] = '\0';

        item.key = buf;
        result = hsearch(item, FIND);

        if (result == NULL) {
            printf("Entry not found.\n");
        } else {
            d = (struct data *)result->data;
            printf("Name: %s\nAge: %d\nHeight: %d\nWeight: %d\n",
                   result->key, d->age, d->height, d->weight);
        }
    }

    return 0;
}
11. 注意事项和优化建议

在使用这些算法和函数时,需要注意以下几点:
- 内存管理 :在使用动态内存分配函数(如 malloc )时,要确保及时释放内存,避免内存泄漏。
- 错误处理 :在调用函数时,要检查函数的返回值,进行适当的错误处理,以提高程序的健壮性。
- 性能优化 :根据具体的应用场景,选择合适的算法和数据结构,以提高程序的性能。例如,对于大规模数据的搜索,优先选择二分搜索或哈希表;对于排序操作,使用 qsort 函数。

以下是一些优化建议:
- 哈希表大小 :在使用哈希表时,要合理估计表的大小,避免哈希冲突过多导致性能下降。
- 二叉树平衡 :在使用二叉树时,要注意保持树的平衡,避免出现极端情况导致搜索效率降低。
- 环境变量管理 :在设置环境变量时,要注意变量名的规范和内存管理,避免出现意外错误。

12. 总结

本文详细介绍了UNIX编程中常用的算法和函数,包括线性搜索、二分搜索、哈希表、二叉树、队列操作、排序、环境变量处理以及密码加密等。通过实际的代码示例和应用案例,展示了这些算法和函数的使用方法和适用场景。同时,还提供了一些注意事项和优化建议,帮助读者更好地使用这些算法和函数。

在实际编程中,我们可以根据具体的需求和数据特点,选择最合适的算法和函数,以提高程序的效率和性能。希望本文对读者在UNIX编程中有所帮助。

下面是一个简单的流程图,展示了一个通用的搜索程序的执行流程:

graph TD;
    A[开始] --> B[读取数据];
    B --> C[数据预处理];
    C --> D[用户输入搜索关键字];
    D --> E[选择搜索算法];
    E --> F[执行搜索];
    F --> G{是否找到};
    G -- 是 --> H[输出结果];
    G -- 否 --> I[输出未找到信息];
    H --> J[结束];
    I --> J;

通过这个流程图,我们可以更清晰地了解搜索程序的执行过程。

希望这些内容能够帮助你在UNIX编程中更好地运用这些算法和函数,提高编程效率和质量。如果你有任何疑问或建议,欢迎留言讨论。

内容概要:本文围绕SecureCRT自动化脚本开发在毕业设计中的应用,系统介绍了如何利用SecureCRT的脚本功能(支持Python、VBScript等)提升计算机、网络工程等相关专业毕业设计的效率质量。文章从关键概念入手,阐明了SecureCRT脚本的核心对象(如crt、Screen、Session)及其在解决多设备调试、重复操作、跨场景验证等毕业设计常见痛点中的价值。通过三个典型应用场景——网络设备配置一致性验证、嵌入式系统稳定性测试、云平台CLI兼容性测试,展示了脚本的实际赋能效果,并以Python实现的交换机端口安全配置验证脚本为例,深入解析了会话管理、屏幕同步、输出解析、异常处理和结果导出等关键技术细节。最后展望了低代码化、AI辅助调试和云边协同等未来发展趋势。; 适合人群:计算机、网络工程、物联网、云计算等相关专业,具备一定编程基础(尤其是Python)的本科或研究生毕业生,以及需要进行设备自动化操作的科研人员; 使用场景及目标:①实现批量网络设备配置的自动验证报告生成;②长时间自动化采集嵌入式系统串口数据;③批量执行云平台CLI命令并分析兼容性差异;目标是提升毕业设计的操作效率、增强实验可复现性数据严谨性; 阅读建议:建议读者结合自身毕业设计课题,参考文中代码案例进行本地实践,重点关注异常处理机制正则表达式的适配,并注意敏感信息(如密码)的加密管理,同时可探索将脚本外部工具(如Excel、数据库)集成以增强结果分析能力。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值