【cs50】Week 5 Data Structures

课程笔记lecture

1. FIFO 队列

queue
enqueue
dequeue

2. LIFO 栈

stack
push
pop
email

3. array 数组

Resizing Arrays

原始

#include <stdio.h>

int main(void)
{
    int list[3];

    list[0] = 1;
    list[1] = 2;
    list[2] = 3;
    for(int i = 0; i < 3; i++)
    {
        printf("%i\n", list[i]);
    }

    return 0;
}

动态分配

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

int main(void)
{
    int *list = malloc(3 * sizeof(int));

    if (list == NULL)
    {
        return 1;
    }

    list[0] = 1;
    list[1] = 2;
    list[2] = 3;

    int *temp = malloc(4 * sizeof(int));

    if (temp == NULL)
    {
        // 重要,防止内存泄露,一定要free之前的
        free(list);
        return 1;
    }

    for(int i = 0; i < 3; i++)
    {
        temp[i] = list[i];
    }
    temp[3] = 4;

    free(list);
    list = temp;

    for(int i = 0; i < 4; i++)
    {
        printf("%i\n", list[i]);
    }

    free(list);
    return 0;
}

4. Linked Lists 链表

. 进入结构体
*
在这里插入图片描述
n->next = NULL

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

typedef struct node
    {
        int number;
        struct node *next;
    } node;

int main(int argc, char *argv[])
{
    node *list = NULL;
    for(int i = 1; i < argc; i++)
    {
        int number = atoi(argv[i]);

        node *n = malloc(sizeof(node));
        if (n == NULL)
        {
            // free memory thus far
            return 1;
        }
        n->number = number;
        n->next = list;
        list = n;

        // print
        node *ptr = list;
        while(ptr != NULL)
        {
            printf("%i\n", ptr->number);
            ptr = ptr->next;
        }
    }

    return 0;
}

5. tree

2叉搜索树

6.hashing 散列

映射
hash function -> hash table
在这里插入图片描述
在这里插入图片描述

在输入中使用const 防止函数更改变量

在这里插入图片描述

返回非负数,使用unsigned int

在这里插入图片描述

tries

在这里插入图片描述
在这里插入图片描述

二、实现链表插入+释放内存

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

typedef struct node
{
    string phrase;
    struct node *next;
} node;

#define LIST_SIZE 2

bool unload(node *list);
void visualizer(node *list);

int main(void)
{
    node *list = NULL;

    // Add items to list
    for (int i = 0; i < LIST_SIZE; i++)
    {
        string phrase = get_string("Enter a new phrase: ");

        // TODO: add phrase to new node in list
        node *n = malloc(sizeof(node));

        if (n == NULL)
        {
            return 1;
        }

        n->phrase = phrase;
        n->next = NULL;

        n->next = list;
        list = n;

        // Visualize list after adding a node.
        visualizer(list);
    }

    // Free all memory used
    if (!unload(list))
    {
        printf("Error freeing the list.\n");
        return 1;
    }

    printf("Freed the list.\n");
    return 0;
}

bool unload(node *list)
{
    // TODO: Free all allocated nodes
    node *ptr = list;

    while(ptr != NULL)
    {
        ptr = list->next;
        free(list);
        list = ptr;
    }

    return true;
}

void visualizer(node *list)
{
    printf("\n+-- List Visualizer --+\n\n");
    while (list != NULL)
    {
        printf("Location %p\nPhrase: \"%s\"\nNext: %p\n\n", list, list->phrase, list->next);
        list = list->next;
    }
    printf("+---------------------+\n\n");
}

三 、hash table

哈希函数

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

typedef struct node
{
    string phrase;
    struct node *next;
} node;

node *table[26];

int hash(string phrase);
bool unload(node *list);
void visualizer(node *list);

int main(void)
{
    // Add items
    for (int i = 0; i < 3; i++)
    {
        string phrase = get_string("Enter a new phrase: ");

        // Find phrase bucket
        int bucket = hash(phrase);
        printf("%s hashes to %i\n", phrase, bucket);
    }
}

// TODO: return the correct bucket for a given phrase
int hash(string phrase)
{
    return toupper(phrase[0] - 'A');
}

Problem Set 5

1. Inheritance

// Simulate genetic inheritance of blood type

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// Each person has two parents and two alleles
typedef struct person
{
    struct person *parents[2];
    char alleles[2];
} person;

const int GENERATIONS = 3;
const int INDENT_LENGTH = 4;

person *create_family(int generations);
void print_family(person *p, int generation);
void free_family(person *p);
char random_allele();

int main(void)
{
    // Seed random number generator
    srand(time(0));

    // Create a new family with three generations
    person *p = create_family(GENERATIONS);

    // Print family tree of blood types
    print_family(p, 0);

    // Free memory
    free_family(p);
}

// Create a new individual with `generations`
person *create_family(int generations)
{
    // TODO: Allocate memory for new person
    person *new_person = malloc(sizeof(person));

    if (new_person == NULL)
    {
        return NULL}

    // If there are still generations left to create
    if (generations > 1)
    {
        // Create two new parents for current person by recursively calling create_family
        person *parent0 = create_family(generations - 1);
        person *parent1 = create_family(generations - 1);

        // TODO: Set parent pointers for current person
        new_person->parents[0] = parent0;
        new_person->parents[1] = parent1;

        // TODO: Randomly assign current person's alleles based on the alleles of their parents
        new_person->allele[0] = parent0->alleles[rand() % 2];
        new_person->allele[1] = parent0->alleles[rand() % 2];
    }

    // If there are no generations left to create
    else
    {
        // TODO: Set parent pointers to NULL
        new_person->parents[0] = NULL;
        new_person->parents[1] = NULL;

        // TODO: Randomly assign alleles
        new_person->allele[0] = random_allele();
        new_person->allele[1] = random_allele();
    }

    // TODO: Return newly created person
    return new_person;
}

// Free `p` and all ancestors of `p`.
void free_family(person *p)
{
    // TODO: Handle base case
    if(p == NULL)
    {
        return;
    }

    // TODO: Free parents recursively
    free_family(p->parents[0]);
    free_family(p->parents[1]);

    // TODO: Free child
    free(p);
}

// Print each family member and their alleles.
void print_family(person *p, int generation)
{
    // Handle base case
    if (p == NULL)
    {
        return;
    }

    // Print indentation
    for (int i = 0; i < generation * INDENT_LENGTH; i++)
    {
        printf(" ");
    }

    // Print person
    if (generation == 0)
    {
        printf("Child (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
    }
    else if (generation == 1)
    {
        printf("Parent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
    }
    else
    {
        for (int i = 0; i < generation - 2; i++)
        {
            printf("Great-");
        }
        printf("Grandparent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
    }

    // Print parents of current generation
    print_family(p->parents[0], generation + 1);
    print_family(p->parents[1], generation + 1);
}

// Randomly chooses a blood type allele.
char random_allele()
{
    int r = rand() % 3;
    if (r == 0)
    {
        return 'A';
    }
    else if (r == 1)
    {
        return 'B';
    }
    else
    {
        return 'O';
    }
}

2. Speller

For this problem, you’ll implement a program that spell-checks a file, a la the below, using a hash table.

// Implements a dictionary's functionality

#include <ctype.h>
#include <stdbool.h>

#include "dictionary.h"

// Represents a node in a hash table
typedef struct node
{
    char word[LENGTH + 1];
    struct node *next;
} node;

// TODO: Choose number of buckets in hash table
const unsigned int N = 26;
unsigned int word_count = 0; // 全局变量,用于计数加载的单词数

// Hash table
node *table[N];

// Returns true if word is in dictionary, else false
bool check(const char *word)
{
    // TODO

    // 计算哈希值
    unsigned int index = hash(word);

    // 获取哈希值对应的链表
    node *cursor = table[index];

    // 遍历list
    while(cursor != NULL)
    {
        // 比较链表中的单词和给定单词,忽略大小写
        if (strcasecmp(cursor->word, word) == 0)
        {
            return true;
        }
        cursor = cursor->next;
    }

    // 不在字典中
    return false;
}

// Hashes word to a number
unsigned int hash(const char *word)
{
    // TODO: Improve this hash function
    unsigned int hash_value = 0;
    int i = 0;

    // 遍历单词的每个字符
    while(word[i] != '\0')
    {
        hash_value += tolower(word[i]);
        i++;
    }
    return hash_value % N;
}

// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
    // TODO

    // Open the dictionary file
    FILE *source = fopen(dictionary, "r");
    if (source == NULL) // 如果文件无法打开,返回 false
    {
        return false;
    }

    // Read each word in the file
    char word[LENGTH + 1];
    while(fscanf(source, "%s", word) != EOF)
    {
        // 为新的哈希表节点创造空间
        node *new_node = malloc(sizeof(node));

        // 如果内存分配失败,返回 false
        if(new_node == NULL)
        {
            fclose(source);
            return false;
        }

        // 将单词复制到新节点
        strcpy(new_node->word, word);

        // 计算哈希值
        int index = hash(word);

        // 插入哈希表
        new_node->next = table[index];
        table[index] = new_node;

        // count
        word_count++;
    }

    // Close the dictionary file
    fclose(source);
    return true;
}

// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
    // TODO
    return word_count;
}

// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
    // TODO
    // 遍历哈希表中的每个桶
    for (int i = 0; i < N; i++)
    {
        // 遍历当前链表
        node *cursor = table[i];
        while (cursor != NULL)
        {
            // 临时保存下一个节点地址
            node *temp = cursor->next;

            // 释放当前节点内存
            free(cursor);

            // 移动到下一个节点
            cursor = temp;
        }
    }

    // 所有节点都被释放
    return true;
}

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值