当前位置:   article > 正文

数据结构和算法一轮

数据结构和算法一轮

前言

本文参考《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顺序表

数据结构:

  1. #include<iostream>
  2. #define MAXSIZE 20 // 定义最大数组大小
  3. using namespace std;
  4. int partition(int* arr, int low, int high);
  5. // 定义一个顺序表结构体
  6. struct Sqlist{
  7. int *elem; // 指向动态分配的数组
  8. int length; // 记录顺序表中的元素数量
  9. };
  10. // 初始化顺序表
  11. int InitList(Sqlist* L){
  12. L->elem = new int[MAXSIZE]; // 动态分配一个整型数组
  13. if(!L->elem){ // 如果分配失败
  14. return 0; // 返回0表示初始化失败
  15. }
  16. L->length = 0; // 初始化长度为0
  17. return 1; // 返回1表示初始化成功
  18. }
  19. // 在顺序表中的第i个位置插入元素e
  20. int ListInsert(Sqlist* L, int i, int e){
  21. if(L->length == MAXSIZE){ // 如果顺序表已满
  22. return 0; // 返回0表示插入失败
  23. }
  24. if(i < 1 || i > L->length + 1){ // 如果插入位置不合法
  25. return 0; // 返回0表示插入失败
  26. }
  27. if(i <= L->length){ // 如果插入位置在表尾或中间
  28. for(int k = L->length - 1; k >= i - 1; k--){ // 将插入位置及其后的元素后移
  29. L->elem[k + 1] = L->elem[k];
  30. }
  31. }
  32. L->elem[i - 1] = e; // 在第i个位置插入元素e
  33. L->length++; // 表长度加1
  34. return 1; // 返回1表示插入成功
  35. }
  36. // 删除顺序表中的第i个位置的元素,并通过*e返回其值
  37. int ListDelete(Sqlist* L, int i, int *e){
  38. if(L->length == 0){ // 如果顺序表为空
  39. return 0; // 返回0表示删除失败
  40. }
  41. if(i < 1 || i > L->length){ // 如果删除位置不合法
  42. return 0; // 返回0表示删除失败
  43. }
  44. *e = L->elem[i - 1]; // 通过*e返回被删除元素的值
  45. if(i < L->length){ // 如果删除位置不是表尾
  46. for(int k = i; k < L->length; k++){ // 将删除位置后的元素前移
  47. L->elem[k - 1] = L->elem[k];
  48. }
  49. }
  50. L->length--; // 表长度减1
  51. return 1; // 返回1表示删除成功
  52. }
  53. // 获取顺序表中的第i个位置的元素,并通过*e返回其值
  54. int GetElem(Sqlist* L, int i, int *e){
  55. if(L->length == 0 || i < 1 || i > L->length){ // 如果表为空或位置不合法
  56. return 0; // 返回0表示获取失败
  57. }
  58. *e = L->elem[i - 1]; // 通过*e返回第i个位置的元素值
  59. return 1; // 返回1表示获取成功
  60. }
  61. // 输出顺序表中的所有元素
  62. void OutPut(Sqlist* L){
  63. for(int i = 0; i < L->length; i++){ // 遍历顺序表
  64. cout << L->elem[i] << " "; // 输出每个元素
  65. }
  66. }
  67. // 快速排序的辅助函数,用于交换两个元素的值
  68. void swap(int* a, int* b) {
  69. int t = *a;
  70. *a = *b;
  71. *b = t;
  72. }
  73. // 快速排序的核心函数
  74. void quickSort(int* arr, int low, int high) {
  75. if (low < high) {
  76. // partitionIndex 是分区操作后基准元素的正确位置
  77. int partitionIndex = partition(arr, low, high);
  78. // 分别对分区前后的子序列进行快速排序
  79. quickSort(arr, low, partitionIndex - 1);
  80. quickSort(arr, partitionIndex + 1, high);
  81. }
  82. }
  83. // 分区操作,将小于基准元素的移到左边,大于基准元素的移到右边
  84. int partition(int* arr, int low, int high) {
  85. int pivot = arr[high]; // 选择最后一个元素作为基准
  86. int i = (low - 1); // 指向比基准小的元素的最后一个位置
  87. for (int j = low; j <= high - 1; j++) {
  88. if (arr[j] < pivot) {
  89. i++; // 发现小于基准的元素,i右移
  90. swap(&arr[i], &arr[j]); // 交换元素
  91. }
  92. }
  93. swap(&arr[i + 1], &arr[high]); // 将基准元素放到正确的位置
  94. return (i + 1); // 返回基准元素的索引
  95. }
  96. // 调用快速排序的函数
  97. void quickSort(Sqlist* L) {
  98. quickSort(L->elem, 0, L->length - 1);
  99. }
  100. int main(){
  101. Sqlist L; // 声明一个顺序表
  102. if(InitList(&L)){ // 初始化顺序表
  103. ListInsert(&L, 1, 10); // 在第1个位置插入元素10
  104. }
  105. quickSort(&L);//对顺序表进行快速排序
  106. OutPut(&L); // 输出顺序表中的所有元素
  107. return 0;
  108. }

1.2单链表

  1. #include<iostream>
  2. #include<vector>
  3. using namespace std;
  4. // 定义单链表节点结构体
  5. struct ListNode {
  6. int val; // 存储节点的值
  7. ListNode* next; // 指向下一个节点的指针
  8. };
  9. // 创建链表
  10. ListNode* CreateList() {
  11. ListNode* head = new ListNode(); // 创建头节点
  12. head->next = nullptr; // 初始化头节点的next指针为空
  13. return head; // 返回头节点
  14. }
  15. // 在链表中插入元素
  16. void Insert(ListNode* head, int i, int val) {
  17. ListNode* current = head; // 初始化current为头节点
  18. while (i-- > 0) { // 循环i次,找到要插入的位置
  19. current = current->next; // current后移
  20. }
  21. if (current) { // 如果current不为空,表示找到了位置
  22. current->next = new ListNode{val, nullptr}; // 创建新节点并连接到链表
  23. }
  24. }
  25. // 删除链表中的元素
  26. void Delete(ListNode* head, int i) {
  27. ListNode* current = head; // 初始化current为头节点
  28. while (i-- > 0) { // 循环i次,找到要删除的位置
  29. current = current->next; // current后移
  30. }
  31. if (current) { // 如果current不为空,表示找到了位置
  32. current->next = current->next->next; // 跳过要删除的节点
  33. delete current->next; // 释放要删除的节点的内存
  34. }
  35. }
  36. // 获取链表中的元素
  37. int Get(ListNode* head, int i) {
  38. ListNode* current = head->next; // 初始化current为头节点的下一个节点
  39. while (i-- > 0) { // 循环i次,找到要获取的元素
  40. current = current->next; // current后移
  41. }
  42. return current ? current->val : -1; // 返回元素值,如果current为空,返回-1
  43. }
  44. // 输出链表
  45. void Output(ListNode* head) {
  46. ListNode* current = head->next; // 初始化current为头节点的下一个节点
  47. while (current) { // 循环直到current为空
  48. cout << current->val << " "; // 输出当前节点的值
  49. current = current->next; // current后移
  50. }
  51. }
  52. // 快速排序的辅助函数,用于交换两个元素的值
  53. void swap(ListNode* a, ListNode* b) {
  54. int t = a->val; // 存储a节点的值
  55. a->val = b->val; // 将a节点的值替换为b节点的值
  56. b->val = t; // 将b节点的值替换为a节点的值
  57. }
  58. // 快速排序的核心函数
  59. void quickSort(ListNode* head) {
  60. quickSort(head, nullptr, nullptr); // 递归函数,参数low和high分别指向链表的开始和结束
  61. }
  62. // 分区操作,将小于基准元素的移到左边,大于基准元素的移到右边
  63. void quickSort(ListNode* head, ListNode* low, ListNode* high) {
  64. if (low != high) { // 如果low和high不指向同一个节点,说明链表中有多个元素
  65. ListNode* pivot = partition(head, low, high); // 执行分区操作
  66. // 对分区前后的子序列进行快速排序
  67. quickSort(head, low, pivot); // 对分区前的子序列进行排序
  68. quickSort(head, pivot->next, high); // 对分区后的子序列进行排序
  69. }
  70. }
  71. // 分区操作,将小于基准元素的移到左边,大于基准元素的移到右边
  72. ListNode* partition(ListNode* head, ListNode* low, ListNode* high) {
  73. ListNode* pivot = high->next; // 选择最后一个节点作为基准
  74. ListNode* i = low; // 指向比基准小的元素的最后一个位置
  75. while (low != high) { // 当low和high不指向同一个节点时,继续分区
  76. if (low->next->val < pivot->val) { // 如果low->next的值小于基准值
  77. i = low; // i后移到low的位置
  78. swap(i->next, low->next); // 交换low->next和i->next的值
  79. }
  80. low = low->next; // low后移
  81. }
  82. swap(i->next, pivot); // 将基准值放到正确的位置
  83. return i; // 返回基准值的索引
  84. }
  85. int main() {
  86. ListNode* head = CreateList(); // 创建链表
  87. Insert(head, 0, 5); // 在第0个位置插入元素5
  88. Insert(head, 1, 3); // 在第1个位置插入元素3
  89. Insert(head, 2, 7); // 在第2个位置插入元素7
  90. Insert(head, 3, 1); // 在第3个位置插入元素1
  91. cout << "Before sorting:" << endl; // 输出排序前的链表
  92. Output(head);
  93. quickSort(head); // 对链表进行快速排序
  94. cout << "After sorting:" << endl; // 输出排序后的链表
  95. Output(head);
  96. return 0; // 程序结束
  97. }

1.3循环链表

 1.4双向链表

  1. #include<iostream>
  2. #include<vector>
  3. using namespace std;
  4. // 定义双向链表节点结构体
  5. struct DoublyListNode {
  6. int val;
  7. DoublyListNode* prev;
  8. DoublyListNode* next;
  9. };
  10. // 创建双向链表
  11. DoublyListNode* CreateDoublyList() {
  12. DoublyListNode* head = new DoublyListNode(); // 创建头节点
  13. head->prev = nullptr;
  14. head->next = nullptr;
  15. return head;
  16. }
  17. // 在双向链表中插入元素
  18. void Insert(DoublyListNode* head, int i, int val) {
  19. DoublyListNode* current = head;
  20. while (i-- > 0) {
  21. current = current->next;
  22. }
  23. if (current) {
  24. current->next = new DoublyListNode{val, current, nullptr};
  25. current->next->prev = current;
  26. }
  27. }
  28. // 删除双向链表中的元素
  29. void Delete(DoublyListNode* head, int i) {
  30. DoublyListNode* current = head;
  31. while (i-- > 0) {
  32. current = current->next;
  33. }
  34. if (current) {
  35. current->prev->next = current->next;
  36. if (current->next) {
  37. current->next->prev = current->prev;
  38. }
  39. delete current;
  40. }
  41. }
  42. // 获取双向链表中的元素
  43. int Get(DoublyListNode* head, int i) {
  44. DoublyListNode* current = head->next;
  45. while (i-- > 0) {
  46. current = current->next;
  47. }
  48. return current ? current->val : -1;
  49. }
  50. // 输出双向链表
  51. void Output(DoublyListNode* head) {
  52. DoublyListNode* current = head->next;
  53. while (current) {
  54. cout << current->val << " ";
  55. current = current->next;
  56. }
  57. }
  58. // 快速排序的辅助函数,用于交换两个元素的值
  59. void swap(DoublyListNode* a, DoublyListNode* b) {
  60. int t = a->val;
  61. a->val = b->val;
  62. b->val = t;
  63. }
  64. // 快速排序的核心函数
  65. void quickSort(DoublyListNode* head) {
  66. quickSort(head, nullptr, nullptr);
  67. }
  68. // 分区操作,将小于基准元素的移到左边,大于基准元素的移到右边
  69. void quickSort(DoublyListNode* head, DoublyListNode* low, DoublyListNode* high) {
  70. if (low != high) {
  71. DoublyListNode* pivot = partition(head, low, high);
  72. // 分别对分区前后的子序列进行快速排序
  73. quickSort(head, low, pivot);
  74. quickSort(head, pivot->next, high);
  75. }
  76. }
  77. // 分区操作,将小于基准元素的移到左边,大于基准元素的移到右边
  78. DoublyListNode* partition(DoublyListNode* head, DoublyListNode* low, DoublyListNode* high) {
  79. DoublyListNode* pivot = high->next; // 选择最后一个节点作为基准
  80. DoublyListNode* i = low; // 指向比基准小的元素的最后一个位置
  81. while (low != high) { // 当low和high不指向同一个节点时,继续分区
  82. if (low->next->val < pivot->val) { // 如果low->next的值小于基准值
  83. i = low; // i后移到low的位置
  84. swap(i->next, low->next); // 交换low->next和i->next的值
  85. }
  86. low = low->next; // low后移
  87. }
  88. swap(i->next, pivot); // 将基准值放到正确的位置
  89. return i; // 返回基准值的索引
  90. }
  91. int main() {
  92. DoublyListNode* head = CreateDoublyList(); // 创建双向链表
  93. Insert(head, 0, 5); // 在第0个位置插入元素5
  94. Insert(head, 1, 3); // 在第1个位置插入元素3
  95. Insert(head, 2, 7); // 在第2个位置插入元素7
  96. Insert(head, 3, 1); // 在第3个位置插入元素1
  97. cout << "Before sorting:" << endl; // 输出排序前的链表
  98. Output(head);
  99. quickSort(head); // 对链表进行快速排序
  100. cout << "After sorting:" << endl; // 输出排序后的链表
  101. Output(head);
  102. return 0; // 程序结束
  103. }

第二章栈和队列

2.1栈

  1. #include<iostream>
  2. using namespace std;
  3. // 定义顺序栈结构体
  4. struct Stack {
  5. int *elem; // 指向动态分配的数组
  6. int top; // 栈顶指针
  7. int maxSize; // 栈的最大容量
  8. };
  9. // 创建顺序栈
  10. Stack* CreateStack(int maxSize) {
  11. Stack* stack = new Stack();
  12. stack->elem = new int[maxSize];
  13. stack->top = -1; // 初始化栈顶指针为-1
  14. stack->maxSize = maxSize;
  15. return stack;
  16. }
  17. // 入栈操作
  18. void Push(Stack* stack, int val) {
  19. if (stack->top < stack->maxSize - 1) { // 如果栈未满
  20. stack->elem[++stack->top] = val; // 栈顶指针后移,并赋值
  21. } else {
  22. cout << "栈已满,无法入栈。" << endl;
  23. }
  24. }
  25. // 出栈操作
  26. int Pop(Stack* stack) {
  27. if (stack->top >= 0) { // 如果栈非空
  28. return stack->elem[stack->top--]; // 返回栈顶元素,并栈顶指针前移
  29. } else {
  30. cout << "栈为空,无法出栈。" << endl;
  31. return -1; // 返回-1表示栈空
  32. }
  33. }
  34. // 获取栈顶元素
  35. int GetTop(Stack* stack) {
  36. if (stack->top >= 0) { // 如果栈非空
  37. return stack->elem[stack->top]; // 返回栈顶元素
  38. } else {
  39. cout << "栈为空,无法获取栈顶元素。" << endl;
  40. return -1; // 返回-1表示栈空
  41. }
  42. }
  43. // 判断栈是否为空
  44. bool IsEmpty(Stack* stack) {
  45. return stack->top < 0; // 如果栈顶指针小于0,则栈为空
  46. }
  47. // 释放栈内存
  48. void DestroyStack(Stack* stack) {
  49. delete[] stack->elem; // 释放数组内存
  50. delete stack; // 释放栈结构体内存
  51. }
  52. int main() {
  53. Stack* stack = CreateStack(10); // 创建一个最大容量为10的顺序栈
  54. cout << "入栈元素: 10, 20, 30, 40, 50" << endl;
  55. Push(stack, 10);
  56. Push(stack, 20);
  57. Push(stack, 30);
  58. Push(stack, 40);
  59. Push(stack, 50);
  60. cout << "栈顶元素: " << GetTop(stack) << endl;
  61. cout << "出栈元素: " << Pop(stack) << endl;
  62. cout << "栈顶元素: " << GetTop(stack) << endl;
  63. cout << "栈是否为空: " << (IsEmpty(stack) ? "是" : "否") << endl;
  64. DestroyStack(stack); // 释放栈内存
  65. return 0;
  66. }

2.2共享栈 

 

  1. #include<iostream>
  2. #include<mutex>
  3. using namespace std;
  4. // 定义共享栈结构体
  5. struct SharedStack {
  6. int *elem; // 指向动态分配的数组
  7. int top; // 栈顶指针
  8. int maxSize; // 栈的最大容量
  9. mutex mtx; // 互斥锁
  10. };
  11. // 创建共享栈
  12. SharedStack* CreateSharedStack(int maxSize) {
  13. SharedStack* stack = new SharedStack();
  14. stack->elem = new int[maxSize];
  15. stack->top = -1; // 初始化栈顶指针为-1
  16. stack->maxSize = maxSize;
  17. return stack;
  18. }
  19. // 入栈操作
  20. void Push(SharedStack* stack, int val) {
  21. lock_guard<mutex> lock(stack->mtx); // 使用互斥锁保护临界区
  22. if (stack->top < stack->maxSize - 1) { // 如果栈未满
  23. stack->elem[++stack->top] = val; // 栈顶指针后移,并赋值
  24. } else {
  25. cout << "栈已满,无法入栈。" << endl;
  26. }
  27. }
  28. // 出栈操作
  29. int Pop(SharedStack* stack) {
  30. lock_guard<mutex> lock(stack->mtx); // 使用互斥锁保护临界区
  31. if (stack->top >= 0) { // 如果栈非空
  32. return stack->elem[stack->top--]; // 返回栈顶元素,并栈顶指针前移
  33. } else {
  34. cout << "栈为空,无法出栈。" << endl;
  35. return -1; // 返回-1表示栈空
  36. }
  37. }
  38. // 获取栈顶元素
  39. int GetTop(SharedStack* stack) {
  40. lock_guard<mutex> lock(stack->mtx); // 使用互斥锁保护临界区
  41. if (stack->top >= 0) { // 如果栈非空
  42. return stack->elem[stack->top]; // 返回栈顶元素
  43. } else {
  44. cout << "栈为空,无法获取栈顶元素。" << endl;
  45. return -1; // 返回-1表示栈空
  46. }
  47. }
  48. // 判断栈是否为空
  49. bool IsEmpty(SharedStack* stack) {
  50. lock_guard<mutex> lock(stack->mtx); // 使用互斥锁保护临界区
  51. return stack->top < 0; // 如果栈顶指针小于0,则栈为空
  52. }
  53. // 释放栈内存
  54. void DestroySharedStack(SharedStack* stack) {
  55. lock_guard<mutex> lock(stack->mtx); // 使用互斥锁保护临界区
  56. delete[] stack->elem; // 释放数组内存
  57. delete stack; // 释放栈结构体内存
  58. }
  59. int main() {
  60. SharedStack* sharedStack = CreateSharedStack(10); // 创建一个最大容量为10的共享栈
  61. cout << "入栈元素: 10, 20, 30, 40, 50" << endl;
  62. Push(sharedStack, 10);
  63. Push(sharedStack, 20);
  64. Push(sharedStack, 30);
  65. Push(sharedStack, 40);
  66. Push(sharedStack, 50);
  67. cout << "栈顶元素: " << GetTop(sharedStack) << endl;
  68. cout << "出栈元素: " << Pop(sharedStack) << endl;
  69. cout << "栈顶元素: " << GetTop(sharedStack) << endl;
  70. cout << "栈是否为空: " << (IsEmpty(sharedStack) ? "是" : "否") << endl;
  71. DestroySharedStack(sharedStack); // 释放栈内存
  72. return 0;
  73. }

2.3链栈

  1. #include<iostream>
  2. using namespace std;
  3. // 定义链栈节点结构体
  4. struct StackNode {
  5. int val;
  6. StackNode* next;
  7. };
  8. // 创建链栈
  9. StackNode* CreateStack() {
  10. StackNode* head = new StackNode(); // 创建头节点
  11. head->next = nullptr;
  12. return head;
  13. }
  14. // 入栈操作
  15. void Push(StackNode* head, int val) {
  16. StackNode* newNode = new StackNode{val, nullptr}; // 创建新节点
  17. newNode->next = head->next; // 将新节点链接到链表
  18. head->next = newNode; // 头节点指向新节点
  19. }
  20. // 出栈操作
  21. int Pop(StackNode* head) {
  22. if (head->next == nullptr) {
  23. cout << "栈为空,无法出栈。" << endl;
  24. return -1; // 返回-1表示栈空
  25. }
  26. StackNode* temp = head->next; // 临时节点
  27. int val = temp->val; // 保存要返回的值
  28. head->next = temp->next; // 头节点指向下一个节点
  29. delete temp; // 释放临时节点
  30. return val; // 返回栈顶元素
  31. }
  32. // 获取栈顶元素
  33. int GetTop(StackNode* head) {
  34. if (head->next == nullptr) {
  35. cout << "栈为空,无法获取栈顶元素。" << endl;
  36. return -1; // 返回-1表示栈空
  37. }
  38. return head->next->val; // 返回栈顶元素
  39. }
  40. // 判断栈是否为空
  41. bool IsEmpty(StackNode* head) {
  42. return head->next == nullptr; // 如果头节点的next指针为空,则栈为空
  43. }
  44. int main() {
  45. StackNode* stack = CreateStack(); // 创建链栈
  46. cout << "入栈元素: 10, 20, 30, 40, 50" << endl;
  47. Push(stack, 10);
  48. Push(stack, 20);
  49. Push(stack, 30);
  50. Push(stack, 40);
  51. Push(stack, 50);
  52. cout << "栈顶元素: " << GetTop(stack) << endl;
  53. cout << "出栈元素: " << Pop(stack) << endl;
  54. cout << "栈顶元素: " << GetTop(stack) << endl;
  55. cout << "栈是否为空: " << (IsEmpty(stack) ? "是" : "否") << endl;
  56. return 0;
  57. }

2.4队列

  1. #include<iostream>
  2. #include<vector>
  3. using namespace std;
  4. // 定义队列结构体
  5. struct Queue {
  6. vector<int> elements; // 使用vector来存储队列元素
  7. };
  8. // 创建队列
  9. Queue* CreateQueue() {
  10. return new Queue(); // 创建队列对象
  11. }
  12. // 入队操作
  13. void Enqueue(Queue* queue, int val) {
  14. queue->elements.push_back(val); // 将元素添加到队列末尾
  15. }
  16. // 出队操作
  17. int Dequeue(Queue* queue) {
  18. if (queue->elements.empty()) { // 如果队列为空
  19. cout << "队列为空,无法出队。" << endl;
  20. return -1; // 返回-1表示队空
  21. }
  22. int val = queue->elements.front(); // 获取队首元素
  23. queue->elements.erase(queue->elements.begin()); // 删除队首元素
  24. return val; // 返回队首元素
  25. }
  26. // 获取队首元素
  27. int GetFront(Queue* queue) {
  28. if (queue->elements.empty()) { // 如果队列为空
  29. cout << "队列为空,无法获取队首元素。" << endl;
  30. return -1; // 返回-1表示队空
  31. }
  32. return queue->elements.front(); // 返回队首元素
  33. }
  34. // 判断队列是否为空
  35. bool IsEmpty(Queue* queue) {
  36. return queue->elements.empty(); // 如果队列大小为0,则队列为空
  37. }
  38. int main() {
  39. Queue* queue = CreateQueue(); // 创建队列
  40. cout << "入队元素: 10, 20, 30, 40, 50" << endl;
  41. Enqueue(queue, 10);
  42. Enqueue(queue, 20);
  43. Enqueue(queue, 30);
  44. Enqueue(queue, 40);
  45. Enqueue(queue, 50);
  46. cout << "队首元素: " << GetFront(queue) << endl;
  47. cout << "出队元素: " << Dequeue(queue) << endl;
  48. cout << "队首元素: " << GetFront(queue) << endl;
  49. cout << "队列是否为空: " << (IsEmpty(queue) ? "是" : "否") << endl;
  50. return 0;
  51. }

2.5循环队列

  1. #include<iostream>
  2. using namespace std;
  3. // 定义循环队列结构体
  4. struct CircularQueue {
  5. int *arr; // 指向动态分配的数组
  6. int front; // 队首指针
  7. int rear; // 队尾指针
  8. int maxSize; // 队列的最大容量
  9. };
  10. // 创建循环队列
  11. CircularQueue* CreateCircularQueue(int maxSize) {
  12. CircularQueue* queue = new CircularQueue();
  13. queue->arr = new int[maxSize];
  14. queue->front = -1; // 初始化队首指针为-1
  15. queue->rear = -1; // 初始化队尾指针为-1
  16. queue->maxSize = maxSize;
  17. return queue;
  18. }
  19. // 入队操作
  20. void Enqueue(CircularQueue* queue, int val) {
  21. if ((queue->rear + 1) % queue->maxSize == queue->front) { // 如果队列已满
  22. cout << "队列已满,无法入队。" << endl;
  23. return;
  24. }
  25. if (queue->front == -1) { // 如果队列为空,队首指针指向0
  26. queue->front = 0;
  27. }
  28. queue->rear = (queue->rear + 1) % queue->maxSize; // 队尾指针后移
  29. queue->arr[queue->rear] = val; // 在队尾插入新元素
  30. }
  31. // 出队操作
  32. int Dequeue(CircularQueue* queue) {
  33. if (queue->front == -1) { // 如果队列为空
  34. cout << "队列为空,无法出队。" << endl;
  35. return -1; // 返回-1表示队空
  36. }
  37. int val = queue->arr[queue->front]; // 获取队首元素
  38. queue->front = (queue->front + 1) % queue->maxSize; // 队首指针后移
  39. return val; // 返回队首元素
  40. }
  41. // 获取队首元素
  42. int GetFront(CircularQueue* queue) {
  43. if (queue->front == -1) { // 如果队列为空
  44. cout << "队列为空,无法获取队首元素。" << endl;
  45. return -1; // 返回-1表示队空
  46. }
  47. return queue->arr[queue->front]; // 返回队首元素
  48. }
  49. // 判断队列是否为空
  50. bool IsEmpty(CircularQueue* queue) {
  51. return queue->front == -1; // 如果队首指针为-1,则队列为空
  52. }
  53. int main() {
  54. CircularQueue* circularQueue = CreateCircularQueue(5); // 创建一个最大容量为5的循环队列
  55. cout << "入队元素: 10, 20, 30, 40, 50" << endl;
  56. Enqueue(circularQueue, 10);
  57. Enqueue(circularQueue, 20);
  58. Enqueue(circularQueue, 30);
  59. Enqueue(circularQueue, 40);
  60. Enqueue(circularQueue, 50);
  61. cout << "队首元素: " << GetFront(circularQueue) << endl;
  62. cout << "出队元素: " << Dequeue(circularQueue) << endl;
  63. cout << "队首元素: " << GetFront(circularQueue) << endl;
  64. cout << "队列是否为空: " << (IsEmpty(circularQueue) ? "是" : "否") << endl;
  65. return 0;
  66. }

2.6链队列

  1. #include<iostream>
  2. using namespace std;
  3. // 定义链队列节点结构体
  4. struct QueueNode {
  5. int val;
  6. QueueNode* next;
  7. };
  8. // 创建链队列
  9. QueueNode* CreateQueue() {
  10. QueueNode* head = new QueueNode(); // 创建头节点
  11. head->next = nullptr;
  12. return head;
  13. }
  14. // 入队操作
  15. void Enqueue(QueueNode* head, int val) {
  16. QueueNode* newNode = new QueueNode{val, nullptr}; // 创建新节点
  17. newNode->next = head->next; // 将新节点链接到链表
  18. head->next = newNode; // 头节点指向新节点
  19. }
  20. // 出队操作
  21. int Dequeue(QueueNode* head) {
  22. if (head->next == nullptr) {
  23. cout << "队列为空,无法出队。" << endl;
  24. return -1; // 返回-1表示队空
  25. }
  26. QueueNode* temp = head->next; // 临时节点
  27. int val = temp->val; // 保存要返回的值
  28. head->next = temp->next; // 头节点指向下一个节点
  29. delete temp; // 释放临时节点
  30. return val; // 返回队首元素
  31. }
  32. // 获取队首元素
  33. int GetFront(QueueNode* head) {
  34. if (head->next == nullptr) {
  35. cout << "队列为空,无法获取队首元素。" << endl;
  36. return -1; // 返回-1表示队空
  37. }
  38. return head->next->val; // 返回队首元素
  39. }
  40. // 判断队列是否为空
  41. bool IsEmpty(QueueNode* head) {
  42. return head->next == nullptr; // 如果头节点的next指针为空,则队列空
  43. }
  44. int main() {
  45. QueueNode* queue = CreateQueue(); // 创建链队列
  46. cout << "入队元素: 10, 20, 30, 40, 50" << endl;
  47. Enqueue(queue, 10);
  48. Enqueue(queue, 20);
  49. Enqueue(queue, 30);
  50. Enqueue(queue, 40);
  51. Enqueue(queue, 50);
  52. cout << "队首元素: " << GetFront(queue) << endl;
  53. cout << "出队元素: " << Dequeue(queue) << endl;
  54. cout << "队首元素: " << GetFront(queue) << endl;
  55. cout << "队列是否为空: " << (IsEmpty(queue) ? "是" : "否") << endl;
  56. return 0;
  57. }

2.7双端队列

  1. #include<iostream>
  2. using namespace std;
  3. // 定义双端队列节点结构体
  4. struct DequeNode {
  5. int val;
  6. DequeNode* next;
  7. DequeNode* prev;
  8. };
  9. // 创建双端队列
  10. DequeNode* CreateDeque() {
  11. DequeNode* head = new DequeNode(); // 创建头节点
  12. DequeNode* tail = new DequeNode(); // 创建尾节点
  13. head->next = tail;
  14. tail->prev = head;
  15. return head;
  16. }
  17. // 入队操作(队尾)
  18. void EnqueueRear(DequeNode* head, int val) {
  19. DequeNode* newNode = new DequeNode{val, nullptr, head->next}; // 创建新节点
  20. head->next->prev = newNode; // 新节点的prev指向当前队尾
  21. head->next = newNode; // 头节点的next指向新节点
  22. }
  23. // 入队操作(队首)
  24. void EnqueueFront(DequeNode* head, int val) {
  25. DequeNode* newNode = new DequeNode{val, head, nullptr}; // 创建新节点
  26. head->prev->next = newNode; // 新节点的next指向当前队首
  27. head->prev = newNode; // 头节点的prev指向新节点
  28. }
  29. // 出队操作(队首)
  30. int DequeueFront(DequeNode* head) {
  31. if (head->next == nullptr) { // 如果队列为空
  32. cout << "队列为空,无法出队。" << endl;
  33. return -1; // 返回-1表示队空
  34. }
  35. DequeNode* temp = head->next; // 临时节点
  36. int val = temp->val; // 保存要返回的值
  37. head->next = temp->next; // 头节点的next指向下一个节点
  38. temp->next->prev = head; // 新节点的prev指向队首
  39. delete temp; // 释放临时节点
  40. return val; // 返回队首元素
  41. }
  42. // 出队操作(队尾)
  43. int DequeueRear(DequeNode* head) {
  44. if (head->next == nullptr) { // 如果队列为空
  45. cout << "队列为空,无法出队。" << endl;
  46. return -1; // 返回-1表示队空
  47. }
  48. DequeNode* temp = head->next; // 临时节点
  49. int val = temp->val; // 保存要返回的值
  50. temp->prev->next = temp->next; // 尾节点的prev指向下一个节点
  51. temp->next->prev = temp->prev; // 新节点的prev指向队尾
  52. delete temp; // 释放临时节点
  53. return val; // 返回队尾元素
  54. }
  55. // 获取队首元素
  56. int GetFront(DequeNode* head) {
  57. if (head->next == nullptr) { // 如果队列为空
  58. cout << "队列为空,无法获取队首元素。" << endl;
  59. return -1; // 返回-1表示队空
  60. }
  61. return head->next->val; // 返回队首元素
  62. }
  63. // 获取队尾元素
  64. int GetRear(DequeNode* head) {
  65. if (head->next == nullptr) { // 如果队列为空
  66. cout << "队列为空,无法获取队尾元素。" << endl;
  67. return -1; // 返回-1表示队空
  68. }
  69. return head->next->val; // 返回队尾元素
  70. }
  71. // 判断队列是否为空
  72. bool IsEmpty(DequeNode* head) {
  73. return head->next == nullptr; // 如果头节点的next指针为空,则队列为空
  74. }
  75. int main() {
  76. DequeNode* deque = CreateDeque(); // 创建双端队列
  77. cout << "入队元素: 10, 20, 30, 40, 50" << endl;
  78. EnqueueFront(deque, 10);
  79. EnqueueFront(deque, 20);
  80. EnqueueRear(deque, 30);
  81. EnqueueRear(deque, 40);
  82. EnqueueFront(deque, 50);
  83. cout << "队首元素: " << GetFront(deque) << endl;
  84. cout << "队尾元素: " << GetRear(deque) << endl;
  85. cout << "出队元素: " << DequeueFront(deque) << endl;
  86. cout << "队首元素: " << GetFront(deque) << endl;
  87. cout << "队列是否为空: " << (IsEmpty(deque) ? "是" : "否") << endl;
  88. return 0;
  89. }

第三章串

3.1串

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

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

3.2定长顺序存储

  1. #define MAXLEN 255 //预定义最大串长为255
  2. struct sstring{
  3. char ch[MAXLEN]; //每个分量存储一个字符
  4. int length; //串的实际长度
  5. };

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

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

3.3堆分配存储

  1. struct HString{
  2. char *ch; //按串长分配存储区,ch指向串的基地址
  3. int length; //串的长度
  4. };

 3.4串的基本操作

  1. StrAssign(&T, chars): 赋值操作。把串T赋值为 chars
  2. Strcopy(&T, S): 复制操作。由串S复制得到串T。
  3. StrEmpty(S): 判空操作。若S为空串,则返回TRUE,否则返回 FALSE
  4. StrCompare(S,T): 比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
  5. StrEngth(S): 求串长。返回串S的元素个数
  6. Substring(&Sub,S,pos,1en):求子串。用Sub返回串S的第pos个字符起长度为len的子串。
  7. Concat(&T,S1,S2): 串联接。用T返回由S1和S2联接而成的新串。
  8. Index(S,T): 定位操作。若主串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0
  9. int Index(Sring S, String T){
  10. int i = 1, n = StrLength(S), m = StrLength(T);
  11. String sub;
  12. while(i <= n-m+1){
  13. SubString(sub, S, i, m); //取主串第i个位置,长度为m的串给sub
  14. if(StrCompare(sub, T) != 0){
  15. ++i;
  16. }else{
  17. return i; //返回子串在主串中的位置
  18. }
  19. }
  20. return 0; //S中不存在与T相等的子串
  21. }
  22. Clearstring(&S): 清空操作。将S清为空串
  23. Destroystring(&S): 销毁串。将串S销毁

3.5串的模式匹配(BF)

  1. int Index(SString S, SString T){
  2. int i = 1, j = 1;
  3. while(i <= S.length && j <= T.length){
  4. if(S.ch[i] == T.ch[j]){
  5. ++i; ++j; //继续比较后继字符
  6. }else{
  7. //指针后退重新开始匹配
  8. i = i-j+2;
  9. j = 1;
  10. }
  11. }
  12. if(j > T.length){
  13. return i - T.length;
  14. }else{
  15. return 0;
  16. }
  17. }

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层最多有2^{k-1}个结点。

3、高度为h的二叉树至多有2^{h}-1个结点。

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之间都有路径)。

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

顶点的度,入度和出度:

边的权和网:

稠密图,稀疏图:

路径,路径长度和回路:

简单路径:顶点不重复。

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

图的存储及操作

邻接矩阵

邻接表

十字链表

邻接多重表 

第八章 排序

插入排序

直接插入

  1. void InsertSort(int A[],int n){
  2. int i,j;
  3. for(i=2;i<=n;i++){
  4. if(A[i]<A[i-1]){
  5. A[0]=A[i];//将当前元素放入哨兵
  6. for(j=i-1;A[0]<A[j];--j){
  7. A[j+1]=A[j];//向后移位
  8. }
  9. A[j+1]=A[0];//将当前元素插入
  10. }
  11. }
  12. }

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

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

折半插入 

  1. void InsertSort(int A[],int n){
  2. int i,j,min,mid,max;
  3. for(i=2;i<=n;i++){
  4. A[0]=A[i];//将当前元素放入哨兵
  5. min=1;max=i-1;
  6. while(min<=max){//无论如何都要折半查找
  7. mid=(min+max)/2;
  8. if(A[mid]>A[0]){
  9. max=mid-1;
  10. } else{
  11. min=mid+1;
  12. }
  13. }
  14. for(j=i-1;j>=max;--j){//向后移位
  15. A[j+1]=A[j];
  16. }
  17. A[max+1]=A[0];
  18. }
  19. }

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

时间效率:O(n²)。

希尔排序

  1. void ShellSort(int A[],int n){
  2. int dk,i,j;
  3. for(dk=n/2;dk>=1;dk=dk/2){//确定增量变化
  4. for(i=dk+1;i<=n;i++){//从数组中间向后遍历
  5. if(A[i]<A[i-dk]){
  6. A[0]=A[i];
  7. for(j=i-dk;j>0&&A[0]<A[j];j-=dk){//向后移位
  8. A[j+dk]=A[j];
  9. }
  10. A[j+dk]=A[0];
  11. }
  12. }
  13. }
  14. }

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

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

交换排序

冒泡排序

  1. void BubbleSort(int A[],int n){
  2. for(int i=0;i<n-1;i++){//一遍使最大值在第一个,n遍排好
  3. bool flag=false;//表示本趟冒泡是否发生交换的标志
  4. for(int j=n-1;j>i;j--){
  5. if(A[j-1]>A[j]){
  6. int m=A[j-1];
  7. A[j-1]=A[j];
  8. A[j]=m;
  9. flag=true;
  10. }
  11. }
  12. if(flag==false)//如果不需要调整
  13. return;
  14. }
  15. }

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

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

快速排序

  1. #include <stdio.h>
  2. int partition(int arr[], int low, int high);
  3. void swap(int *xp, int *yp);
  4. // 快速排序函数
  5. void quickSort(int arr[], int low, int high) {
  6. if (low < high) {
  7. int pi = partition(arr, low, high);
  8. // 递归排序左半部分
  9. quickSort(arr, low, pi - 1);
  10. // 递归排序右半部分
  11. quickSort(arr, pi + 1, high);
  12. }
  13. }
  14. // 用于快速排序的辅助函数,用于分区
  15. int partition(int arr[], int low, int high) {
  16. int pivot = arr[high]; // 选择最后一个元素作为基准
  17. int i = (low - 1); // 初始化指向比基准小的元素的指针
  18. for (int j = low; j <= high - 1; j++) {
  19. // 如果当前元素小于或等于基准,则交换元素
  20. if (arr[j] <= pivot) {
  21. i++;
  22. swap(&arr[i], &arr[j]);
  23. }
  24. }
  25. swap(&arr[i + 1], &arr[high]); // 将基准元素放在正确的位置
  26. return (i + 1);
  27. }
  28. // 交换两个元素
  29. void swap(int *xp, int *yp) {
  30. int temp = *xp;
  31. *xp = *yp;
  32. *yp = temp;
  33. }
  34. int main() {
  35. int arr[] = {12, 23, 28, 35, 37, 39, 50, 60, 78, 90};
  36. int n = sizeof(arr) / sizeof(arr[0]);
  37. quickSort(arr, 0, n - 1);
  38. printf("排序后的数组:\n");
  39. for (int i = 0; i < n; i++)
  40. printf("%d ", arr[i]);
  41. return 0;
  42. }

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/721730
推荐阅读
相关标签
  

闽ICP备14008679号