跳转至

数组和链表

数组

box box

链表

  • 定义: 链表(linked list): 链表由一系列不必在内存中相连的结构组成。每个结构均含有表元素和指向包含该元素后继元的结构指针,称之为next 指针。最后一个单元的next指针指向NULL ;该值由C定义并且不能与其他指针混淆。ANSIC中规定NULL为零。
  • 组成结构 链表的组成单位是「节点 node」对象。每个节点都包含两项数据:节点的“值”和指向下一节点的“引用”。

  • 链表的首个节点被称为“头节点”(header),最后一个节点被称为“尾节点”。

  • 尾节点指向的是“空”,
  • 在 C、C++、Go 和 Rust 等支持指针的语言中,上述的“引用”应被替换为“指针”。
    /* 链表节点结构体 */
    typedef struct ListNode {
        int val;               // 节点值
        struct ListNode *next; // 指向下一节点的指针
    } ListNode;
    
    /* 构造函数 */
    ListNode *newListNode(int val) {
        ListNode *node, *next;
        node = (ListNode *) malloc(sizeof(ListNode));
        node->val = val;
        node->next = NULL;
        return node;
    }
    

常用操作

由于链表的不连续性,防止链表丢失“头”节点。

链表类型

box

List Reverse( List L)
{
    List head, p, s;
    if (L->Next == NULL)
    {
        return L;
    }
    head = L;
    s = L->Next;
    L = s->Next;
    while(L!= NULL)
    {
        p = L->Next;
        L->Next = s;
        s = L;
        L = p;
    }
    head->Next->Next = NULL;
    head->Next = s;
    return head;
}

栈与对列

box

常见操作

方法 描述 时间复杂度
push() 元素入栈(添加至栈底) \(O(1)\)
pop() 栈顶元素出栈 \(O(1)\)
peek() 访问栈顶元素 \(O(1)\)

栈的实现

基于链表

/* 基于链表实现的栈 */
typedef struct 
{
    ListNode *top; // 将头节点作为栈顶
    int size;      // 栈的长度
} LinkedListStack;

/* 构造函数 */
LinkedListStack *newLinkedListStack() 
{
    LinkedListStack *s = malloc(sizeof(LinkedListStack)); //用malloc()分配内存空间
    s->top = NULL;
    s->size = 0;
    return s;
}

/* 析构函数 */
void delLinkedListStack(LinkedListStack *s) 
{
    while (s->top) 
    {
        ListNode *n = s->top->next;
        free(s->top);
        s->top = n;
    }
    free(s);
}

/* 获取栈的长度 */
int size(LinkedListStack *s)
{
    assert(s);
    return s->size;
}

/* 判断栈是否为空 */
bool isEmpty(LinkedListStack *s) 
{
    assert(s);
    return size(s) == 0;
}

/* 访问栈顶元素 */
int peek(LinkedListStack *s) 
{
    assert(s);
    assert(size(s) != 0);
    return s->top->val;
}

/* 入栈 */
void push(LinkedListStack *s, int num) 
{
    assert(s);
    ListNode *node = (ListNode *)malloc(sizeof(ListNode));
    node->next = s->top; // 更新新加节点指针域
    node->val = num;     // 更新新加节点数据域
    s->top = node;       // 更新栈顶
    s->size++;           // 更新栈大小
}

/* 出栈 */
int pop(LinkedListStack *s) 
{
    if (s->size == 0) 
    {
        printf("stack is empty.\n");
        return INT_MAX;
    }
    assert(s);
    int val = peek(s);
    ListNode *tmp = s->top;
    s->top = s->top->next;
    // 释放内存
    free(tmp);
    s->size--;
    return val;
}

基于数组

/* 基于数组实现的栈 */
typedef struct {
    int *data;
    int size;
} ArrayStack;

/* 构造函数 */
ArrayStack *newArrayStack() {
    ArrayStack *s = malloc(sizeof(ArrayStack));
    // 初始化一个大容量,避免扩容
    s->data = malloc(sizeof(int) * MAX_SIZE);
    s->size = 0;
    return s;
}

/* 获取栈的长度 */
int size(ArrayStack *s) {
    return s->size;
}

/* 判断栈是否为空 */
bool isEmpty(ArrayStack *s) {
    return s->size == 0;
}

/* 入栈 */
void push(ArrayStack *s, int num) {
    if (s->size == MAX_SIZE) {
        printf("stack is full.\n");
        return;
    }
    s->data[s->size] = num;
    s->size++;
}

/* 访问栈顶元素 */
int peek(ArrayStack *s) {
    if (s->size == 0) {
        printf("stack is empty.\n");
        return INT_MAX;
    }
    return s->data[s->size - 1];
}

/* 出栈 */
int pop(ArrayStack *s) {
    if (s->size == 0) {
        printf("stack is empty.\n");
        return INT_MAX;
    }
    int val = peek(s);
    s->size--;
    return val;
}

队列

box

常见操作

方法 描述 时间复杂度
push() 元素入队(添加至队尾) \(O(1)\)
pop() 队首元素出队 \(O(1)\)
peek() 访问队首元素 \(O(1)\)

队列的实现

1.基于链表的实现

2. 基于数组的实现

哈希表

哈希表

「哈希表 hash table」,又称「散列表」,其通过建立键 key 与值 value 之间的映射,实现高效的元素查询。具体而言,我们向哈希表输入一个键 key ,则可以在 \(O(1)\) 时间内获取对应的值 value 。

常见操作

初始化、查询操作、添加键值对和删除键值对。

数组实现

哈希函数: 1. 通过某种哈希算法 hash() 计算得到哈希值。 2. 将哈希值对桶数量(数组长度)capacity 取模,从而获取该 key 对应的数组索引 indexindex = hash(key) % capacity box

Supplement from Textbook

抽象数据类型(ADT):并(union),交(intersction),求大小(size),取余数(complement)

表ADT(List)

Definition

链表(linked list): 链表由一系列不必在内存中相连的结构组成。每个结构均含有表元素和指向包含该元素后继元的结构指针,称之为next 指针。最后一个单元的next指针指向NULL ;该值由C定义并且不能与其他指针混淆。ANSIC中规定NULL为零。

栈ADT(Stack)

Definition

  1. Stack: A stack is a list with the restriction that inserts and deletes can be performed in only one position.
  2. Top: the end of the list called the top.
  3. Push: The fundamental operations on a stack are push, which is equivalent to an insert,
  4. pop: pop deletes the most recently inserted element.

  5. The most recently inserted element can be examined prior to performing a pop by use of the top routine.

  6. Error: A pop or top on an empty stack is generally considered an error in the stack ADT. On the other hand, running out of space when performing a push is an implementation error but not an ADT error.