数据结构和算法一轮

前言

本文参考《2025年数据结构考研复习指导(王道论坛组编)》和相关文章,为考试前复习而写。

目录

前言

第一章线性表

1.1顺序表

1.2单链表

1.3循环链表

​1.4双向链表

第二章栈和队列

2.1栈

2.2共享栈

2.3链栈

2.4队列

2.5循环队列

2.6链队列

2.7双端队列

第三章串

3.1串

3.2定长顺序存储

3.3堆分配存储

3.4串的基本操作

3.5串的模式匹配(BF)

3.6kmp

第四章数组

4.1行,列优先存储

4.2压缩存储

1、对称矩阵

​2、三角矩阵​编辑

​3、三对角矩阵​编辑

4、稀疏矩阵

1)三元组

2)带行指针的链表

​3)十字链表

第五章广义表

定义

例题

存储结构

第六章树与二叉树

6.1树

6.1.1基本术语

6.1.2树的性质

6.2二叉树

6.2.1几种特殊的二叉树

6.2.2二叉树的性质

6.2.3二叉树的存储结构

6.2.4二叉树的遍历

6.2.5由遍历序列确定二叉树

6.3线索二叉树

第7章图

图的定义

图的存储及操作

邻接矩阵

邻接表

十字链表

邻接多重表

[第八章 排序](#第八章 排序)

插入排序

直接插入

折半插入

希尔排序

交换排序

冒泡排序

快速排序


第一章线性表

1.1顺序表

数据结构:

cpp 复制代码
#include<iostream>
#define MAXSIZE 20 // 定义最大数组大小
using namespace std;
int partition(int* arr, int low, int high);

// 定义一个顺序表结构体
struct Sqlist{
    int *elem;    // 指向动态分配的数组
    int length;   // 记录顺序表中的元素数量
};

// 初始化顺序表
int InitList(Sqlist* L){
    L->elem = new int[MAXSIZE]; // 动态分配一个整型数组
    if(!L->elem){ // 如果分配失败
        return 0; // 返回0表示初始化失败
    }
    L->length = 0; // 初始化长度为0
    return 1; // 返回1表示初始化成功
}

// 在顺序表中的第i个位置插入元素e
int ListInsert(Sqlist* L, int i, int e){
    if(L->length == MAXSIZE){ // 如果顺序表已满
        return 0; // 返回0表示插入失败
    }
    if(i < 1 || i > L->length + 1){ // 如果插入位置不合法
        return 0; // 返回0表示插入失败
    }
    if(i <= L->length){ // 如果插入位置在表尾或中间
        for(int k = L->length - 1; k >= i - 1; k--){ // 将插入位置及其后的元素后移
            L->elem[k + 1] = L->elem[k];
        }
    }
    L->elem[i - 1] = e; // 在第i个位置插入元素e
    L->length++; // 表长度加1
    return 1; // 返回1表示插入成功
}

// 删除顺序表中的第i个位置的元素,并通过*e返回其值
int ListDelete(Sqlist* L, int i, int *e){
    if(L->length == 0){ // 如果顺序表为空
        return 0; // 返回0表示删除失败
    }
    if(i < 1 || i > L->length){ // 如果删除位置不合法
        return 0; // 返回0表示删除失败
    }
    *e = L->elem[i - 1]; // 通过*e返回被删除元素的值
    if(i < L->length){ // 如果删除位置不是表尾
        for(int k = i; k < L->length; k++){ // 将删除位置后的元素前移
            L->elem[k - 1] = L->elem[k];
        }
    }
    L->length--; // 表长度减1
    return 1; // 返回1表示删除成功
}

// 获取顺序表中的第i个位置的元素,并通过*e返回其值
int GetElem(Sqlist* L, int i, int *e){
    if(L->length == 0 || i < 1 || i > L->length){ // 如果表为空或位置不合法
        return 0; // 返回0表示获取失败
    }
    *e = L->elem[i - 1]; // 通过*e返回第i个位置的元素值
    return 1; // 返回1表示获取成功
}

// 输出顺序表中的所有元素
void OutPut(Sqlist* L){
    for(int i = 0; i < L->length; i++){ // 遍历顺序表
        cout << L->elem[i] << " "; // 输出每个元素
    }
}

// 快速排序的辅助函数,用于交换两个元素的值
void swap(int* a, int* b) {
    int t = *a;
    *a = *b;
    *b = t;
}

// 快速排序的核心函数
void quickSort(int* arr, int low, int high) {
    if (low < high) {
        // partitionIndex 是分区操作后基准元素的正确位置
        int partitionIndex = partition(arr, low, high);

        // 分别对分区前后的子序列进行快速排序
        quickSort(arr, low, partitionIndex - 1);
        quickSort(arr, partitionIndex + 1, high);
    }
}

// 分区操作,将小于基准元素的移到左边,大于基准元素的移到右边
int partition(int* arr, int low, int high) {
    int pivot = arr[high]; // 选择最后一个元素作为基准
    int i = (low - 1); // 指向比基准小的元素的最后一个位置

    for (int j = low; j <= high - 1; j++) {
        if (arr[j] < pivot) {
            i++; // 发现小于基准的元素,i右移
            swap(&arr[i], &arr[j]); // 交换元素
        }
    }
    swap(&arr[i + 1], &arr[high]); // 将基准元素放到正确的位置
    return (i + 1); // 返回基准元素的索引
}

// 调用快速排序的函数
void quickSort(Sqlist* L) {
    quickSort(L->elem, 0, L->length - 1);
}
int main(){
    Sqlist L; // 声明一个顺序表
    if(InitList(&L)){ // 初始化顺序表
        ListInsert(&L, 1, 10); // 在第1个位置插入元素10
    }
    quickSort(&L);//对顺序表进行快速排序 
    OutPut(&L); // 输出顺序表中的所有元素
    return 0;
}

1.2单链表

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;

// 定义单链表节点结构体
struct ListNode {
    int val; // 存储节点的值
    ListNode* next; // 指向下一个节点的指针
};

// 创建链表
ListNode* CreateList() {
    ListNode* head = new ListNode(); // 创建头节点
    head->next = nullptr; // 初始化头节点的next指针为空
    return head; // 返回头节点
}

// 在链表中插入元素
void Insert(ListNode* head, int i, int val) {
    ListNode* current = head; // 初始化current为头节点
    while (i-- > 0) { // 循环i次,找到要插入的位置
        current = current->next; // current后移
    }
    if (current) { // 如果current不为空,表示找到了位置
        current->next = new ListNode{val, nullptr}; // 创建新节点并连接到链表
    }
}

// 删除链表中的元素
void Delete(ListNode* head, int i) {
    ListNode* current = head; // 初始化current为头节点
    while (i-- > 0) { // 循环i次,找到要删除的位置
        current = current->next; // current后移
    }
    if (current) { // 如果current不为空,表示找到了位置
        current->next = current->next->next; // 跳过要删除的节点
        delete current->next; // 释放要删除的节点的内存
    }
}

// 获取链表中的元素
int Get(ListNode* head, int i) {
    ListNode* current = head->next; // 初始化current为头节点的下一个节点
    while (i-- > 0) { // 循环i次,找到要获取的元素
        current = current->next; // current后移
    }
    return current ? current->val : -1; // 返回元素值,如果current为空,返回-1
}

// 输出链表
void Output(ListNode* head) {
    ListNode* current = head->next; // 初始化current为头节点的下一个节点
    while (current) { // 循环直到current为空
        cout << current->val << " "; // 输出当前节点的值
        current = current->next; // current后移
    }
}

// 快速排序的辅助函数,用于交换两个元素的值
void swap(ListNode* a, ListNode* b) {
    int t = a->val; // 存储a节点的值
    a->val = b->val; // 将a节点的值替换为b节点的值
    b->val = t; // 将b节点的值替换为a节点的值
}

// 快速排序的核心函数
void quickSort(ListNode* head) {
    quickSort(head, nullptr, nullptr); // 递归函数,参数low和high分别指向链表的开始和结束
}

// 分区操作,将小于基准元素的移到左边,大于基准元素的移到右边
void quickSort(ListNode* head, ListNode* low, ListNode* high) {
    if (low != high) { // 如果low和high不指向同一个节点,说明链表中有多个元素
        ListNode* pivot = partition(head, low, high); // 执行分区操作

        // 对分区前后的子序列进行快速排序
        quickSort(head, low, pivot); // 对分区前的子序列进行排序
        quickSort(head, pivot->next, high); // 对分区后的子序列进行排序
    }
}

// 分区操作,将小于基准元素的移到左边,大于基准元素的移到右边
ListNode* partition(ListNode* head, ListNode* low, ListNode* high) {
    ListNode* pivot = high->next; // 选择最后一个节点作为基准
    ListNode* i = low; // 指向比基准小的元素的最后一个位置

    while (low != high) { // 当low和high不指向同一个节点时,继续分区
        if (low->next->val < pivot->val) { // 如果low->next的值小于基准值
            i = low; // i后移到low的位置
            swap(i->next, low->next); // 交换low->next和i->next的值
        }
        low = low->next; // low后移
    }
    swap(i->next, pivot); // 将基准值放到正确的位置
    return i; // 返回基准值的索引
}

int main() {
    ListNode* head = CreateList(); // 创建链表
    Insert(head, 0, 5); // 在第0个位置插入元素5
    Insert(head, 1, 3); // 在第1个位置插入元素3
    Insert(head, 2, 7); // 在第2个位置插入元素7
    Insert(head, 3, 1); // 在第3个位置插入元素1

    cout << "Before sorting:" << endl; // 输出排序前的链表
    Output(head);

    quickSort(head); // 对链表进行快速排序

    cout << "After sorting:" << endl; // 输出排序后的链表
    Output(head);

    return 0; // 程序结束
}

1.3循环链表

1.4双向链表

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;

// 定义双向链表节点结构体
struct DoublyListNode {
    int val;
    DoublyListNode* prev;
    DoublyListNode* next;
};

// 创建双向链表
DoublyListNode* CreateDoublyList() {
    DoublyListNode* head = new DoublyListNode(); // 创建头节点
    head->prev = nullptr;
    head->next = nullptr;
    return head;
}

// 在双向链表中插入元素
void Insert(DoublyListNode* head, int i, int val) {
    DoublyListNode* current = head;
    while (i-- > 0) {
        current = current->next;
    }
    if (current) {
        current->next = new DoublyListNode{val, current, nullptr};
        current->next->prev = current;
    }
}

// 删除双向链表中的元素
void Delete(DoublyListNode* head, int i) {
    DoublyListNode* current = head;
    while (i-- > 0) {
        current = current->next;
    }
    if (current) {
        current->prev->next = current->next;
        if (current->next) {
            current->next->prev = current->prev;
        }
        delete current;
    }
}

// 获取双向链表中的元素
int Get(DoublyListNode* head, int i) {
    DoublyListNode* current = head->next;
    while (i-- > 0) {
        current = current->next;
    }
    return current ? current->val : -1;
}

// 输出双向链表
void Output(DoublyListNode* head) {
    DoublyListNode* current = head->next;
    while (current) {
        cout << current->val << " ";
        current = current->next;
    }
}

// 快速排序的辅助函数,用于交换两个元素的值
void swap(DoublyListNode* a, DoublyListNode* b) {
    int t = a->val;
    a->val = b->val;
    b->val = t;
}

// 快速排序的核心函数
void quickSort(DoublyListNode* head) {
    quickSort(head, nullptr, nullptr);
}

// 分区操作,将小于基准元素的移到左边,大于基准元素的移到右边
void quickSort(DoublyListNode* head, DoublyListNode* low, DoublyListNode* high) {
    if (low != high) {
        DoublyListNode* pivot = partition(head, low, high);

        // 分别对分区前后的子序列进行快速排序
        quickSort(head, low, pivot);
        quickSort(head, pivot->next, high);
    }
}

// 分区操作,将小于基准元素的移到左边,大于基准元素的移到右边
DoublyListNode* partition(DoublyListNode* head, DoublyListNode* low, DoublyListNode* high) {
    DoublyListNode* pivot = high->next; // 选择最后一个节点作为基准
    DoublyListNode* i = low; // 指向比基准小的元素的最后一个位置

    while (low != high) { // 当low和high不指向同一个节点时,继续分区
        if (low->next->val < pivot->val) { // 如果low->next的值小于基准值
            i = low; // i后移到low的位置
            swap(i->next, low->next); // 交换low->next和i->next的值
        }
        low = low->next; // low后移
    }
    swap(i->next, pivot); // 将基准值放到正确的位置
    return i; // 返回基准值的索引
}

int main() {
    DoublyListNode* head = CreateDoublyList(); // 创建双向链表
    Insert(head, 0, 5); // 在第0个位置插入元素5
    Insert(head, 1, 3); // 在第1个位置插入元素3
    Insert(head, 2, 7); // 在第2个位置插入元素7
    Insert(head, 3, 1); // 在第3个位置插入元素1

    cout << "Before sorting:" << endl; // 输出排序前的链表
    Output(head);

    quickSort(head); // 对链表进行快速排序

    cout << "After sorting:" << endl; // 输出排序后的链表
    Output(head);

    return 0; // 程序结束
}

第二章栈和队列

2.1栈

cpp 复制代码
#include<iostream>
using namespace std;

// 定义顺序栈结构体
struct Stack {
    int *elem; // 指向动态分配的数组
    int top; // 栈顶指针
    int maxSize; // 栈的最大容量
};

// 创建顺序栈
Stack* CreateStack(int maxSize) {
    Stack* stack = new Stack();
    stack->elem = new int[maxSize];
    stack->top = -1; // 初始化栈顶指针为-1
    stack->maxSize = maxSize;
    return stack;
}

// 入栈操作
void Push(Stack* stack, int val) {
    if (stack->top < stack->maxSize - 1) { // 如果栈未满
        stack->elem[++stack->top] = val; // 栈顶指针后移,并赋值
    } else {
        cout << "栈已满,无法入栈。" << endl;
    }
}

// 出栈操作
int Pop(Stack* stack) {
    if (stack->top >= 0) { // 如果栈非空
        return stack->elem[stack->top--]; // 返回栈顶元素,并栈顶指针前移
    } else {
        cout << "栈为空,无法出栈。" << endl;
        return -1; // 返回-1表示栈空
    }
}

// 获取栈顶元素
int GetTop(Stack* stack) {
    if (stack->top >= 0) { // 如果栈非空
        return stack->elem[stack->top]; // 返回栈顶元素
    } else {
        cout << "栈为空,无法获取栈顶元素。" << endl;
        return -1; // 返回-1表示栈空
    }
}

// 判断栈是否为空
bool IsEmpty(Stack* stack) {
    return stack->top < 0; // 如果栈顶指针小于0,则栈为空
}

// 释放栈内存
void DestroyStack(Stack* stack) {
    delete[] stack->elem; // 释放数组内存
    delete stack; // 释放栈结构体内存
}

int main() {
    Stack* stack = CreateStack(10); // 创建一个最大容量为10的顺序栈
    
    cout << "入栈元素: 10, 20, 30, 40, 50" << endl;
    Push(stack, 10);
    Push(stack, 20);
    Push(stack, 30);
    Push(stack, 40);
    Push(stack, 50);
    
    cout << "栈顶元素: " << GetTop(stack) << endl;
    cout << "出栈元素: " << Pop(stack) << endl;
    cout << "栈顶元素: " << GetTop(stack) << endl;
    
    cout << "栈是否为空: " << (IsEmpty(stack) ? "是" : "否") << endl;
    
    DestroyStack(stack); // 释放栈内存
    
    return 0;
}

2.2共享栈

cpp 复制代码
#include<iostream>
#include<mutex>
using namespace std;

// 定义共享栈结构体
struct SharedStack {
    int *elem; // 指向动态分配的数组
    int top; // 栈顶指针
    int maxSize; // 栈的最大容量
    mutex mtx; // 互斥锁
};

// 创建共享栈
SharedStack* CreateSharedStack(int maxSize) {
    SharedStack* stack = new SharedStack();
    stack->elem = new int[maxSize];
    stack->top = -1; // 初始化栈顶指针为-1
    stack->maxSize = maxSize;
    return stack;
}

// 入栈操作
void Push(SharedStack* stack, int val) {
    lock_guard<mutex> lock(stack->mtx); // 使用互斥锁保护临界区
    if (stack->top < stack->maxSize - 1) { // 如果栈未满
        stack->elem[++stack->top] = val; // 栈顶指针后移,并赋值
    } else {
        cout << "栈已满,无法入栈。" << endl;
    }
}

// 出栈操作
int Pop(SharedStack* stack) {
    lock_guard<mutex> lock(stack->mtx); // 使用互斥锁保护临界区
    if (stack->top >= 0) { // 如果栈非空
        return stack->elem[stack->top--]; // 返回栈顶元素,并栈顶指针前移
    } else {
        cout << "栈为空,无法出栈。" << endl;
        return -1; // 返回-1表示栈空
    }
}

// 获取栈顶元素
int GetTop(SharedStack* stack) {
    lock_guard<mutex> lock(stack->mtx); // 使用互斥锁保护临界区
    if (stack->top >= 0) { // 如果栈非空
        return stack->elem[stack->top]; // 返回栈顶元素
    } else {
        cout << "栈为空,无法获取栈顶元素。" << endl;
        return -1; // 返回-1表示栈空
    }
}

// 判断栈是否为空
bool IsEmpty(SharedStack* stack) {
    lock_guard<mutex> lock(stack->mtx); // 使用互斥锁保护临界区
    return stack->top < 0; // 如果栈顶指针小于0,则栈为空
}

// 释放栈内存
void DestroySharedStack(SharedStack* stack) {
    lock_guard<mutex> lock(stack->mtx); // 使用互斥锁保护临界区
    delete[] stack->elem; // 释放数组内存
    delete stack; // 释放栈结构体内存
}

int main() {
    SharedStack* sharedStack = CreateSharedStack(10); // 创建一个最大容量为10的共享栈
    
    cout << "入栈元素: 10, 20, 30, 40, 50" << endl;
    Push(sharedStack, 10);
    Push(sharedStack, 20);
    Push(sharedStack, 30);
    Push(sharedStack, 40);
    Push(sharedStack, 50);
    
    cout << "栈顶元素: " << GetTop(sharedStack) << endl;
    cout << "出栈元素: " << Pop(sharedStack) << endl;
    cout << "栈顶元素: " << GetTop(sharedStack) << endl;
    
    cout << "栈是否为空: " << (IsEmpty(sharedStack) ? "是" : "否") << endl;
    
    DestroySharedStack(sharedStack); // 释放栈内存
    
    return 0;
}

2.3链栈

cpp 复制代码
#include<iostream>
using namespace std;

// 定义链栈节点结构体
struct StackNode {
    int val;
    StackNode* next;
};

// 创建链栈
StackNode* CreateStack() {
    StackNode* head = new StackNode(); // 创建头节点
    head->next = nullptr;
    return head;
}

// 入栈操作
void Push(StackNode* head, int val) {
    StackNode* newNode = new StackNode{val, nullptr}; // 创建新节点
    newNode->next = head->next; // 将新节点链接到链表
    head->next = newNode; // 头节点指向新节点
}

// 出栈操作
int Pop(StackNode* head) {
    if (head->next == nullptr) {
        cout << "栈为空,无法出栈。" << endl;
        return -1; // 返回-1表示栈空
    }
    StackNode* temp = head->next; // 临时节点
    int val = temp->val; // 保存要返回的值
    head->next = temp->next; // 头节点指向下一个节点
    delete temp; // 释放临时节点
    return val; // 返回栈顶元素
}

// 获取栈顶元素
int GetTop(StackNode* head) {
    if (head->next == nullptr) {
        cout << "栈为空,无法获取栈顶元素。" << endl;
        return -1; // 返回-1表示栈空
    }
    return head->next->val; // 返回栈顶元素
}

// 判断栈是否为空
bool IsEmpty(StackNode* head) {
    return head->next == nullptr; // 如果头节点的next指针为空,则栈为空
}

int main() {
    StackNode* stack = CreateStack(); // 创建链栈
    
    cout << "入栈元素: 10, 20, 30, 40, 50" << endl;
    Push(stack, 10);
    Push(stack, 20);
    Push(stack, 30);
    Push(stack, 40);
    Push(stack, 50);
    
    cout << "栈顶元素: " << GetTop(stack) << endl;
    cout << "出栈元素: " << Pop(stack) << endl;
    cout << "栈顶元素: " << GetTop(stack) << endl;
    
    cout << "栈是否为空: " << (IsEmpty(stack) ? "是" : "否") << endl;
    
    return 0;
}

2.4队列

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;

// 定义队列结构体
struct Queue {
    vector<int> elements; // 使用vector来存储队列元素
};

// 创建队列
Queue* CreateQueue() {
    return new Queue(); // 创建队列对象
}

// 入队操作
void Enqueue(Queue* queue, int val) {
    queue->elements.push_back(val); // 将元素添加到队列末尾
}

// 出队操作
int Dequeue(Queue* queue) {
    if (queue->elements.empty()) { // 如果队列为空
        cout << "队列为空,无法出队。" << endl;
        return -1; // 返回-1表示队空
    }
    int val = queue->elements.front(); // 获取队首元素
    queue->elements.erase(queue->elements.begin()); // 删除队首元素
    return val; // 返回队首元素
}

// 获取队首元素
int GetFront(Queue* queue) {
    if (queue->elements.empty()) { // 如果队列为空
        cout << "队列为空,无法获取队首元素。" << endl;
        return -1; // 返回-1表示队空
    }
    return queue->elements.front(); // 返回队首元素
}

// 判断队列是否为空
bool IsEmpty(Queue* queue) {
    return queue->elements.empty(); // 如果队列大小为0,则队列为空
}

int main() {
    Queue* queue = CreateQueue(); // 创建队列
    
    cout << "入队元素: 10, 20, 30, 40, 50" << endl;
    Enqueue(queue, 10);
    Enqueue(queue, 20);
    Enqueue(queue, 30);
    Enqueue(queue, 40);
    Enqueue(queue, 50);
    
    cout << "队首元素: " << GetFront(queue) << endl;
    cout << "出队元素: " << Dequeue(queue) << endl;
    cout << "队首元素: " << GetFront(queue) << endl;
    
    cout << "队列是否为空: " << (IsEmpty(queue) ? "是" : "否") << endl;
    
    return 0;
}

2.5循环队列

cpp 复制代码
#include<iostream>
using namespace std;

// 定义循环队列结构体
struct CircularQueue {
    int *arr; // 指向动态分配的数组
    int front; // 队首指针
    int rear; // 队尾指针
    int maxSize; // 队列的最大容量
};

// 创建循环队列
CircularQueue* CreateCircularQueue(int maxSize) {
    CircularQueue* queue = new CircularQueue();
    queue->arr = new int[maxSize];
    queue->front = -1; // 初始化队首指针为-1
    queue->rear = -1; // 初始化队尾指针为-1
    queue->maxSize = maxSize;
    return queue;
}

// 入队操作
void Enqueue(CircularQueue* queue, int val) {
    if ((queue->rear + 1) % queue->maxSize == queue->front) { // 如果队列已满
        cout << "队列已满,无法入队。" << endl;
        return;
    }
    if (queue->front == -1) { // 如果队列为空,队首指针指向0
        queue->front = 0;
    }
    queue->rear = (queue->rear + 1) % queue->maxSize; // 队尾指针后移
    queue->arr[queue->rear] = val; // 在队尾插入新元素
}

// 出队操作
int Dequeue(CircularQueue* queue) {
    if (queue->front == -1) { // 如果队列为空
        cout << "队列为空,无法出队。" << endl;
        return -1; // 返回-1表示队空
    }
    int val = queue->arr[queue->front]; // 获取队首元素
    queue->front = (queue->front + 1) % queue->maxSize; // 队首指针后移
    return val; // 返回队首元素
}

// 获取队首元素
int GetFront(CircularQueue* queue) {
    if (queue->front == -1) { // 如果队列为空
        cout << "队列为空,无法获取队首元素。" << endl;
        return -1; // 返回-1表示队空
    }
    return queue->arr[queue->front]; // 返回队首元素
}

// 判断队列是否为空
bool IsEmpty(CircularQueue* queue) {
    return queue->front == -1; // 如果队首指针为-1,则队列为空
}

int main() {
    CircularQueue* circularQueue = CreateCircularQueue(5); // 创建一个最大容量为5的循环队列
    
    cout << "入队元素: 10, 20, 30, 40, 50" << endl;
    Enqueue(circularQueue, 10);
    Enqueue(circularQueue, 20);
    Enqueue(circularQueue, 30);
    Enqueue(circularQueue, 40);
    Enqueue(circularQueue, 50);
    
    cout << "队首元素: " << GetFront(circularQueue) << endl;
    cout << "出队元素: " << Dequeue(circularQueue) << endl;
    cout << "队首元素: " << GetFront(circularQueue) << endl;
    
    cout << "队列是否为空: " << (IsEmpty(circularQueue) ? "是" : "否") << endl;
    
    return 0;
}

2.6链队列

cpp 复制代码
#include<iostream>
using namespace std;

// 定义链队列节点结构体
struct QueueNode {
    int val;
    QueueNode* next;
};

// 创建链队列
QueueNode* CreateQueue() {
    QueueNode* head = new QueueNode(); // 创建头节点
    head->next = nullptr;
    return head;
}

// 入队操作
void Enqueue(QueueNode* head, int val) {
    QueueNode* newNode = new QueueNode{val, nullptr}; // 创建新节点
    newNode->next = head->next; // 将新节点链接到链表
    head->next = newNode; // 头节点指向新节点
}

// 出队操作
int Dequeue(QueueNode* head) {
    if (head->next == nullptr) {
        cout << "队列为空,无法出队。" << endl;
        return -1; // 返回-1表示队空
    }
    QueueNode* temp = head->next; // 临时节点
    int val = temp->val; // 保存要返回的值
    head->next = temp->next; // 头节点指向下一个节点
    delete temp; // 释放临时节点
    return val; // 返回队首元素
}

// 获取队首元素
int GetFront(QueueNode* head) {
    if (head->next == nullptr) {
        cout << "队列为空,无法获取队首元素。" << endl;
        return -1; // 返回-1表示队空
    }
    return head->next->val; // 返回队首元素
}

// 判断队列是否为空
bool IsEmpty(QueueNode* head) {
    return head->next == nullptr; // 如果头节点的next指针为空,则队列空
}

int main() {
    QueueNode* queue = CreateQueue(); // 创建链队列
    
    cout << "入队元素: 10, 20, 30, 40, 50" << endl;
    Enqueue(queue, 10);
    Enqueue(queue, 20);
    Enqueue(queue, 30);
    Enqueue(queue, 40);
    Enqueue(queue, 50);
    
    cout << "队首元素: " << GetFront(queue) << endl;
    cout << "出队元素: " << Dequeue(queue) << endl;
    cout << "队首元素: " << GetFront(queue) << endl;
    
    cout << "队列是否为空: " << (IsEmpty(queue) ? "是" : "否") << endl;
    
    return 0;
}

2.7双端队列

cpp 复制代码
#include<iostream>
using namespace std;

// 定义双端队列节点结构体
struct DequeNode {
    int val;
    DequeNode* next;
    DequeNode* prev;
};

// 创建双端队列
DequeNode* CreateDeque() {
    DequeNode* head = new DequeNode(); // 创建头节点
    DequeNode* tail = new DequeNode(); // 创建尾节点
    head->next = tail;
    tail->prev = head;
    return head;
}

// 入队操作(队尾)
void EnqueueRear(DequeNode* head, int val) {
    DequeNode* newNode = new DequeNode{val, nullptr, head->next}; // 创建新节点
    head->next->prev = newNode; // 新节点的prev指向当前队尾
    head->next = newNode; // 头节点的next指向新节点
}

// 入队操作(队首)
void EnqueueFront(DequeNode* head, int val) {
    DequeNode* newNode = new DequeNode{val, head, nullptr}; // 创建新节点
    head->prev->next = newNode; // 新节点的next指向当前队首
    head->prev = newNode; // 头节点的prev指向新节点
}

// 出队操作(队首)
int DequeueFront(DequeNode* head) {
    if (head->next == nullptr) { // 如果队列为空
        cout << "队列为空,无法出队。" << endl;
        return -1; // 返回-1表示队空
    }
    DequeNode* temp = head->next; // 临时节点
    int val = temp->val; // 保存要返回的值
    head->next = temp->next; // 头节点的next指向下一个节点
    temp->next->prev = head; // 新节点的prev指向队首
    delete temp; // 释放临时节点
    return val; // 返回队首元素
}

// 出队操作(队尾)
int DequeueRear(DequeNode* head) {
    if (head->next == nullptr) { // 如果队列为空
        cout << "队列为空,无法出队。" << endl;
        return -1; // 返回-1表示队空
    }
    DequeNode* temp = head->next; // 临时节点
    int val = temp->val; // 保存要返回的值
    temp->prev->next = temp->next; // 尾节点的prev指向下一个节点
    temp->next->prev = temp->prev; // 新节点的prev指向队尾
    delete temp; // 释放临时节点
    return val; // 返回队尾元素
}

// 获取队首元素
int GetFront(DequeNode* head) {
    if (head->next == nullptr) { // 如果队列为空
        cout << "队列为空,无法获取队首元素。" << endl;
        return -1; // 返回-1表示队空
    }
    return head->next->val; // 返回队首元素
}

// 获取队尾元素
int GetRear(DequeNode* head) {
    if (head->next == nullptr) { // 如果队列为空
        cout << "队列为空,无法获取队尾元素。" << endl;
        return -1; // 返回-1表示队空
    }
    return head->next->val; // 返回队尾元素
}

// 判断队列是否为空
bool IsEmpty(DequeNode* head) {
    return head->next == nullptr; // 如果头节点的next指针为空,则队列为空
}

int main() {
    DequeNode* deque = CreateDeque(); // 创建双端队列
    
    cout << "入队元素: 10, 20, 30, 40, 50" << endl;
    EnqueueFront(deque, 10);
    EnqueueFront(deque, 20);
    EnqueueRear(deque, 30);
    EnqueueRear(deque, 40);
    EnqueueFront(deque, 50);
    
    cout << "队首元素: " << GetFront(deque) << endl;
    cout << "队尾元素: " << GetRear(deque) << endl;
    
    cout << "出队元素: " << DequeueFront(deque) << endl;
    cout << "队首元素: " << GetFront(deque) << endl;
    
    cout << "队列是否为空: " << (IsEmpty(deque) ? "是" : "否") << endl;
    
    return 0;
}

第三章串

3.1串

串( string)是由零个或多个字符组成的有限序列,又名叫字符串。

空串:n = 0 n=0n=0时的串称为空串。
空格串:是只包含空格的串。注意它与空串的区别,空格串是有内容有长度的,而且可以不止一个空格。
子串与主串:串中任意个数的连续字符组成的子序列称为该串的子串,相应地,包含子串的串称为主串。
子串在主串中的位置就是子串的第一个字符在主串中的序号。

3.2定长顺序存储

java 复制代码
#define MAXLEN 255	//预定义最大串长为255
struct sstring{
	char ch[MAXLEN];	//每个分量存储一个字符
	int length;	//串的实际长度
};

串的实际长度只能小于等于MAXLEN,超过预定义长度的串值会被舍去,称为截断。

串长有两种表示方法: 一是如上述定义描述的那样,用一个额外的变量len来存放串的长度;二是在串值后面加一一个不计入串长的结束标记字符"\0"

3.3堆分配存储

java 复制代码
struct HString{
	char *ch;	//按串长分配存储区,ch指向串的基地址
	int length;	//串的长度
};

3.4串的基本操作

java 复制代码
StrAssign(&T, chars): 赋值操作。把串T赋值为 chars
Strcopy(&T, S): 复制操作。由串S复制得到串T。
StrEmpty(S): 判空操作。若S为空串,则返回TRUE,否则返回 FALSE
StrCompare(S,T): 比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。
StrEngth(S): 求串长。返回串S的元素个数
Substring(&Sub,S,pos,1en):求子串。用Sub返回串S的第pos个字符起长度为len的子串。
Concat(&T,S1,S2): 串联接。用T返回由S1和S2联接而成的新串。

Index(S,T): 定位操作。若主串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0
int Index(Sring S, String T){
	int i = 1, n = StrLength(S), m = StrLength(T);
	String sub;
	while(i <= n-m+1){
		SubString(sub, S, i, m);	//取主串第i个位置,长度为m的串给sub
		if(StrCompare(sub, T) != 0){
			++i;
		}else{
			return i;	//返回子串在主串中的位置
		}
	}
	return 0;	//S中不存在与T相等的子串
}

Clearstring(&S): 清空操作。将S清为空串
Destroystring(&S): 销毁串。将串S销毁

3.5串的模式匹配(BF)

java 复制代码
int Index(SString S, SString T){
	int i = 1, j = 1;
	while(i <= S.length && j <= T.length){
		if(S.ch[i] == T.ch[j]){
			++i; ++j;	//继续比较后继字符
		}else{
			//指针后退重新开始匹配
			i = i-j+2;
			j = 1;
		}
	}
	if(j > T.length){
		return i - T.length;
	}else{
		return 0;
	}
}

3.6kmp

第四章数组

4.1行,列优先存储

1、行优先

2、列优先

4.2压缩存储

1、对称矩阵

2、三角矩阵

3、三对角矩阵

4、稀疏矩阵

1)三元组
2)带行指针的链表
3)十字链表

第五章广义表

定义

例题

存储结构

原子结点

表结点

第六章树与二叉树

6.1树

6.1.1基本术语

祖先:考虑结点K,从根A到结点K的唯一路径上的所有其他结点,称为结点K的祖先。

子孙:结点B的子孙包括E,F,K,L。

双亲:结点K的双亲为结点E。

孩子:K为E的孩子。

兄弟:有相同双亲的结点为兄弟。K和L为兄弟。

堂兄弟:双亲在同一层的结点互为堂兄弟。K和M互为堂兄弟。

结点的度:树中一个结点的孩子个数。E的度为2.

树的度:树中结点的最大度数。该树的为3.

分支结点:度大于0的结点(非终端结点)。

叶结点:度为0(没有孩子结点)。

结点的深度:结点所在的层次。K为4,E为3.

树的高度:树中的最大层数。

有序树:树中结点的各子树从左到右是有次序的,不能互换,否则称无序树。

6.1.2树的性质

6.2二叉树

6.2.1几种特殊的二叉树

满二叉树:即二叉树中的每层都含有最多的结点。除叶结点之外的每个结点度数均为2。

完全二叉树: 若有度为一的结点,则最多只可能有一个,且该结点只有左孩子而无右孩子。

二叉排序树:左子树上所有结点均小于根结点。右子树上所有结点均大于根结点 。左右子树又各是一颗二叉排序树。

平衡二叉树:树中任意一个结点的左子树和右子树的高度之差的绝对值不超过一。

正则二叉树:树中只有度为0或2的结点。

6.2.2二叉树的性质

1、设度为0,1,2的结点个数分别为n0,n1,n2。则结点总数n=n0+n1+n2.即n0=n2+1。

2、非空二叉树的第K层最多有个结点。

3、高度为h的二叉树至多有个结点。

4、

6.2.3二叉树的存储结构

顺序存储

链式存储

6.2.4二叉树的遍历

1、先序遍历

若二叉树为空,则什么都不做;否则,

访问根结点;

先序遍历左子树;

先序遍历右子树;

2、中序遍历

3、后序遍历

4、层次遍历

遍历顺序为:A B C D E F G H I

6.2.5由遍历序列确定二叉树

已知中序序列,再给出其他三种遍历序列中的任意一种,就可以唯一地确定一颗二叉树。

1、先序加中序

在先序序列中,第一个结点一定是二叉树的根节点;

在中序序列中,根节点将中序序列分成左子树和右子树的中序序列;

2、后序加中序

后序序列的最后一个结点为根结点,其余与前序加中序类似。

3、层序加中序

6.3线索二叉树

第7章图

图的定义

有向图:

无向图:

简单图:1、不存在重复边2、不存在顶点到自身的边(无环)。

多重图:某两结点之间边数多于一条;允许顶点通过一条边和自己关联。

完全图:

对于无向图,有n(n-1)/2条边的无向图称为完全图。(任意两个顶点之间都存在边)

对于有向图,有n(n-1)条弧的有向图称为完全图。(任意两个顶点之间都存在方向相反的两条弧)

子图:顶点数和边数都少。

生成子图(极大连通子图):就是图本身。

连通图:

连通分量:无向图中的极大连通子图称为连通分量。

强连通图:有向图中,任意一对顶点都是强连通(v到w和从w到v之间都有路径)。

生成树:对生成树而言,若砍去它的一条边,则会变成非连通图,若加上一条边则会形成一个回路。

顶点的度,入度和出度:

边的权和网:

稠密图,稀疏图:

路径,路径长度和回路:

简单路径:顶点不重复。

距离:最短路径长度,不存在路径则为无穷。

图的存储及操作

邻接矩阵

邻接表

十字链表

邻接多重表

第八章 排序

插入排序

直接插入

cpp 复制代码
void InsertSort(int A[],int n){
	int i,j;
	for(i=2;i<=n;i++){
		if(A[i]<A[i-1]){
			A[0]=A[i];//将当前元素放入哨兵 
			for(j=i-1;A[0]<A[j];--j){
				A[j+1]=A[j];//向后移位 
			}
			A[j+1]=A[0];//将当前元素插入 
		}
		
	}
}

空间效率:使用了个哨兵空间,因而空间复杂度为O(1)。

时间效率:最好情况(不用调整)O(n);最坏情况O(n²)。

折半插入

cpp 复制代码
void InsertSort(int A[],int n){
	int i,j,min,mid,max;
	for(i=2;i<=n;i++){
		A[0]=A[i];//将当前元素放入哨兵
		min=1;max=i-1;
		while(min<=max){//无论如何都要折半查找
			mid=(min+max)/2;
			if(A[mid]>A[0]){
				max=mid-1;
			} else{
				min=mid+1;
			}
		} 
		for(j=i-1;j>=max;--j){//向后移位 
			A[j+1]=A[j];
		}
		A[max+1]=A[0]; 
	}
}

空间效率:使用了个哨兵空间,因而空间复杂度为O(1)。

时间效率:O(n²)。

希尔排序

cpp 复制代码
void ShellSort(int A[],int n){
	int dk,i,j;
	for(dk=n/2;dk>=1;dk=dk/2){//确定增量变化
		for(i=dk+1;i<=n;i++){//从数组中间向后遍历 
			if(A[i]<A[i-dk]){
				A[0]=A[i];
				for(j=i-dk;j>0&&A[0]<A[j];j-=dk){//向后移位 
					A[j+dk]=A[j];
				}
				A[j+dk]=A[0];
			}
		} 
	}
}

空间效率:使用了个暂存空间,因而空间复杂度为O(1)。

时间效率:当n在某个特定范围时O();最坏情况O(n²)。

交换排序

冒泡排序

cpp 复制代码
void BubbleSort(int A[],int n){
	for(int i=0;i<n-1;i++){//一遍使最大值在第一个,n遍排好 
		bool flag=false;//表示本趟冒泡是否发生交换的标志
		for(int j=n-1;j>i;j--){
			if(A[j-1]>A[j]){
				int m=A[j-1];
				A[j-1]=A[j];
				A[j]=m;
				flag=true;
			}
		} 
		if(flag==false)//如果不需要调整 
			return;
	}
}

空间效率:使用了个暂存空间,因而空间复杂度为O(1)。

时间效率:最好情况O(n);最坏情况O(n²);平均时间O(n²)。

快速排序

cpp 复制代码
#include <stdio.h>
int partition(int arr[], int low, int high);
void swap(int *xp, int *yp);

// 快速排序函数
void quickSort(int arr[], int low, int high) {
    if (low < high) {
        int pi = partition(arr, low, high);

        // 递归排序左半部分
        quickSort(arr, low, pi - 1);

        // 递归排序右半部分
        quickSort(arr, pi + 1, high);
    }
}

// 用于快速排序的辅助函数,用于分区
int partition(int arr[], int low, int high) {
    int pivot = arr[high]; // 选择最后一个元素作为基准
    int i = (low - 1); // 初始化指向比基准小的元素的指针

    for (int j = low; j <= high - 1; j++) {
        // 如果当前元素小于或等于基准,则交换元素
        if (arr[j] <= pivot) {
            i++;
            swap(&arr[i], &arr[j]);
        }
    }
    swap(&arr[i + 1], &arr[high]); // 将基准元素放在正确的位置
    return (i + 1);
}

// 交换两个元素
void swap(int *xp, int *yp) {
    int temp = *xp;
    *xp = *yp;
    *yp = temp;
}

int main() {
    int arr[] = {12, 23, 28, 35, 37, 39, 50, 60, 78, 90};
    int n = sizeof(arr) / sizeof(arr[0]);

    quickSort(arr, 0, n - 1);

    printf("排序后的数组:\n");
    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);

    return 0;
}

空间效率:O(log n);这里 log n 是因为递归调用栈的最大深度是 log n(每个递归调用都会将问题规模减半,直到问题规模小于或等于1)。

时间效率:最坏情况O(n²);平均时间O(n log n)。

相关推荐
blammmp17 分钟前
Java:数据结构-枚举
java·开发语言·数据结构
昂子的博客39 分钟前
基础数据结构——队列(链表实现)
数据结构
lulu_gh_yu1 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
~yY…s<#>3 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
XuanRanDev4 小时前
【每日一题】LeetCode - 三数之和
数据结构·算法·leetcode·1024程序员节
代码猪猪傻瓜coding4 小时前
力扣1 两数之和
数据结构·算法·leetcode
南宫生5 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
weixin_432702266 小时前
代码随想录算法训练营第五十五天|图论理论基础
数据结构·python·算法·深度优先·图论
passer__jw7677 小时前
【LeetCode】【算法】283. 移动零
数据结构·算法·leetcode
爱吃生蚝的于勒8 小时前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法