1.数据结构

数据结构研究的是数据存储的问题,数据结构=个体的存储+个体的关系存储。
算法 = 对存储数据的操作
衡量算法的标准:

  • 时间复杂度:程序执行的次数,而非时间
  • 空间复杂度:程序执行过程中所占用的最大内存
  • 难易程度
  • 健壮性

2.线性结构

2.1 定义

把所有的结点用一根直线穿起来。

2.2 分类

连续存储(数组)、离散存储(链表)

2.2.1连续存储(数组)

看懂一个程序分为三步:流程、每个语句的功能、试数。
参数,长度,有效元素的个数

(1)用C实现面向对象数组:(此处代码省略了数组增长因子Inversion)

image.png

  1. #include <stdio.h>
  2. #include <malloc.h>
  3. #include <stdlib.h> //包含exit函数
  4. struct Array
  5. {
  6. int* pArr;//数组地址
  7. int len;//数组长度
  8. int ctn;//数组有效元素个数
  9. };
  10. void init(struct Array*,int length);//数组初始化
  11. bool is_empty(struct Array*);//数组为空判断
  12. bool is_full(struct Array*);//数组是否满了
  13. bool show_array(struct Array*);//数组打印操作
  14. bool add_array(struct Array*,int value);//数组添加元素操作
  15. int main()
  16. {
  17. struct Array array;
  18. init(&array, 10);
  19. add_array(&array, 4);
  20. show_array(&array);
  21. add_array(&array, 5);
  22. show_array(&array);
  23. }
  24. bool is_full(struct Array* array)
  25. {
  26. if (array->ctn > array->len)
  27. {
  28. return true;
  29. }
  30. else
  31. {
  32. return false;
  33. }
  34. }
  35. bool add_array(struct Array* array, int value)
  36. {
  37. if (is_full(array))
  38. {
  39. printf("数组已满\n");
  40. return false;
  41. }
  42. else
  43. {
  44. int index = array->ctn;
  45. array->pArr[index] = value;
  46. (array->ctn)++;
  47. return true;
  48. }
  49. }
  50. void init(struct Array* array, int length)
  51. {
  52. array->pArr = (int*)malloc(sizeof(int)*length);
  53. if (NULL == array->pArr)
  54. {
  55. printf("未申请到内存空间\n");
  56. exit(-1);//退出函数
  57. }
  58. else
  59. {
  60. array->len = length;
  61. array->ctn = 0;
  62. }
  63. return;
  64. }
  65. bool is_empty(struct Array* array)
  66. {
  67. if (0 == array->ctn)
  68. {
  69. return true;
  70. }
  71. else
  72. {
  73. return false;
  74. }
  75. }
  76. bool show_array(struct Array* array)
  77. {
  78. if (!is_empty(array))
  79. {
  80. for (int i = 0; i < array->ctn; i++)
  81. {
  82. printf("%d\n", array->pArr[i]);
  83. }
  84. printf("\n");
  85. return true;
  86. }
  87. else
  88. {
  89. printf("数组为空!\n");
  90. return false;
  91. }
  92. }

(2)排序

  1. #include <stdio.h>
  2. #include <malloc.h>
  3. #include <stdlib.h> //包含exit函数
  4. struct Array
  5. {
  6. int* pArr;//数组地址
  7. int len;//数组长度
  8. int ctn;//数组有效元素个数
  9. };
  10. void init(struct Array*,int length);
  11. bool is_empty(struct Array*);
  12. bool is_full(struct Array*);
  13. bool show_array(struct Array*);
  14. bool add_array(struct Array*,int value);
  15. bool insert_array(struct Array*, int pos, int val);
  16. void sort_array(struct Array*);
  17. int main()
  18. {
  19. struct Array array;
  20. init(&array, 5);
  21. add_array(&array, 4);
  22. show_array(&array);
  23. add_array(&array, 5);
  24. show_array(&array);
  25. insert_array(&array, 1, 3);
  26. show_array(&array);
  27. v
  28. }
  29. bool is_full(struct Array* array)
  30. {
  31. if (array->ctn > array->len)
  32. {
  33. return true;
  34. }
  35. else
  36. {
  37. return false;
  38. }
  39. }
  40. bool insert_array(struct Array* parray, int pos, int val)
  41. {
  42. if (pos<=parray->ctn)
  43. {
  44. int index = parray->ctn - 1;
  45. for (int i = index; i > pos-1; --i)
  46. {
  47. parray->pArr[index+1] = parray->pArr[index];
  48. }
  49. parray->pArr[pos-1] = val;
  50. parray->ctn++;
  51. return true;
  52. }
  53. else
  54. {
  55. printf("超出数组长度%d\n", parray->len);
  56. return false;
  57. }
  58. }
  59. //冒泡排序法
  60. //两两比较,最外围循环递减,内层循环递增
  61. void sort_array(struct Array* parray)
  62. {
  63. for (int j = parray->ctn - 1; j >0 ; j--)
  64. {
  65. for (int i = 0; i < j; i++)
  66. {
  67. if (parray->pArr[i] > parray->pArr[i + 1]) {
  68. int t = parray->pArr[i];
  69. parray->pArr[i] = parray->pArr[i + 1];
  70. parray->pArr[i + 1] = t;
  71. }
  72. }
  73. }
  74. }
  75. bool add_array(struct Array* array, int value)
  76. {
  77. if (is_full(array))
  78. {
  79. printf("数组已满\n");
  80. return false;
  81. }
  82. else
  83. {
  84. int index = array->ctn;
  85. array->pArr[index] = value;
  86. (array->ctn)++;
  87. return true;
  88. }
  89. }
  90. void init(struct Array* array, int length)
  91. {
  92. array->pArr = (int*)malloc(sizeof(struct Array)*length);
  93. if (NULL == array->pArr)
  94. {
  95. printf("未申请到内存空间\n");
  96. exit(-1);//退出函数
  97. }
  98. else
  99. {
  100. array->len = length;
  101. array->ctn = 0;
  102. }
  103. return;
  104. }
  105. bool is_empty(struct Array* array)
  106. {
  107. if (0 == array->ctn)
  108. {
  109. return true;
  110. }
  111. else
  112. {
  113. return false;
  114. }
  115. }
  116. bool show_array(struct Array* array)
  117. {
  118. if (!is_empty(array))
  119. {
  120. for (int i = 0; i < array->ctn; i++)
  121. {
  122. printf("%d\n", array->pArr[i]);
  123. }
  124. printf("\n");
  125. return true;
  126. }
  127. else
  128. {
  129. printf("数组为空!\n");
  130. return false;
  131. }
  132. }

(3)小知识

typedef 重命名:

  1. #include <stdio.h>
  2. #include <string>
  3. using namespace std;
  4. typedef struct Student // Typedef重命名
  5. {
  6. int Weight;
  7. }ST;//ST等价于struct Student
  8. int main(void)
  9. {
  10. ST st;
  11. st.Weight = 120;
  12. printf("Name = %d\n",st.Weight);
  13. }
  1. #include <stdio.h>
  2. #include <string>
  3. using namespace std;
  4. typedef struct Student // Typedef重命名
  5. {
  6. int Weight;
  7. }* PST;//PST等价于struct Student *;
  8. int main(void)
  9. {
  10. struct Student st;
  11. st.Weight = 120;
  12. PST pst = &st;
  13. pst->Weight = 124;
  14. printf("Name = %d\n",st.Weight);
  15. }
  1. //二合一
  2. #include <stdio.h>
  3. #include <string>
  4. using namespace std;
  5. typedef struct Student // Typedef重命名
  6. {
  7. int Weight;
  8. }* PST,ST;
  9. int main(void)
  10. {
  11. ST st;
  12. st.Weight = 120;
  13. PST pst = &st;
  14. pst->Weight = 124;
  15. printf("Name = %d\n",st.Weight);
  16. }

2.2.2离散存储(链表)

用C实现面向对象Linked
用C实现面向对泛型

(1)链表的重要性:树,图的本质都是链表

(2)定义

n个节点离散分配
彼此通过指针相连
每个节点只有一个前驱节点,每个节点只有一个后续节点
首节点没有前驱节点 尾节点没有后续节点

专业术语:
头节点—首节点————-尾节点
首节点:第一个有效节点
尾节点:最后一个有效节点
头节点:
头节点的数据类型和首节点类型一样
第一个有效节点之前的那个节点
头节点并不存放有效数据
加头节点的目的是为了方便对链表的操作
头指针:指向头节点的指针变量
尾指针:指向尾节点的指针变量

如果希望通过一个函数来对链表进行处理,我们至少需要接受链表的哪些信息:一个参数,头指针
因为我们通过头指针可以推算出链表的其他所有信息
struct Node
{
int data;数据域
struct Node * pNext;指针域
};

(3)分类

单链表
双链表:每个节点有两个指针域
循环链表:
能通过任何一个节点找到其他所有的节点
非循环链表

(4)算法

狭义的算法是与数据存储方式密切相关的,广义的算法与数据存储方式无关。
泛型:利用某种技术达到的效果就是:不同的存储方式执行的操作是相同的。
遍历
查找
清空
销毁
求长度
排序
插入:r=p->pNext;p->pNext = q;q->pNext = r;

(5)链表的优缺点

2.3 链表的创建及遍历

创建
image.png

  1. #include <stdio.h>
  2. typedef struct Node {
  3. int data;//Data Field
  4. struct Node* pNext;// Point Field
  5. }NODE,*PNODE;
  6. void TraverseList(PNODE);
  7. PNODE CreateList();
  8. int main(void) {
  9. PNODE pHead = NULL;
  10. pHead = CreateList();
  11. TraverseList(pHead);
  12. }
  13. PNODE CreateList() {
  14. int len;//Node Ctn
  15. int value;//Node Value
  16. PNODE pHead = (PNODE)malloc(sizeof(NODE));
  17. PNODE pTail = pHead;
  18. pTail->pNext = NULL;
  19. printf("Please input node number:");
  20. scanf_s("%d", &len);
  21. if (len > 0) {
  22. for (int i = 0; i < len; i++)
  23. {
  24. printf("Please input value of %d", i + 1);
  25. scanf_s("%d", &value);
  26. PNODE pNext = (PNODE)malloc(sizeof(NODE));
  27. pNext->data = value;
  28. pTail->pNext = pNext;
  29. pTail = pNext;
  30. pNext->pNext = NULL;//The end node pNext is NULL.
  31. }
  32. }
  33. else {
  34. printf("Please input number more than zero.");
  35. }
  36. return pHead;
  37. }
  38. void TraverseList(PNODE pHead) {
  39. PNODE pTemp = pHead->pNext;
  40. while (NULL != pTemp) {
  41. printf("%d\n", pTemp->data);
  42. pTemp = pTemp->pNext;
  43. }
  44. }

遍历
临时结点p
image.png

  1. #include <stdio.h>
  2. typedef struct Node {
  3. int data;//Data Field
  4. struct Node* pNext;// Point Field
  5. }NODE,*PNODE;
  6. void TraverseList(PNODE);
  7. PNODE CreateList();
  8. int main(void) {
  9. PNODE pHead = NULL;
  10. pHead = CreateList();
  11. TraverseList(pHead);
  12. }
  13. PNODE CreateList() {
  14. int len;//Node Ctn
  15. int value;//Node Value
  16. PNODE pHead = (PNODE)malloc(sizeof(NODE));
  17. PNODE pTail = pHead;
  18. pTail->pNext = NULL;
  19. printf("Please input node number:");
  20. scanf_s("%d", &len);
  21. if (len > 0) {
  22. for (int i = 0; i < len; i++)
  23. {
  24. printf("Please input value of %d", i + 1);
  25. scanf_s("%d", &value);
  26. PNODE pNext = (PNODE)malloc(sizeof(NODE));
  27. pNext->data = value;
  28. pTail->pNext = pNext;
  29. pTail = pNext;
  30. pNext->pNext = NULL;//The end node pNext is NULL.
  31. }
  32. }
  33. else {
  34. printf("Please input number more than zero.");
  35. }
  36. return pHead;
  37. }
  38. void TraverseList(PNODE pHead) {
  39. PNODE pTemp = pHead->pNext;
  40. while (NULL != pTemp) {
  41. printf("%d\n", pTemp->data);
  42. pTemp = pTemp->pNext;
  43. }
  44. }

2.4 应用

栈、队列

2.4.1栈实现

栈:先进后出,压栈出栈。image.png

  1. #include <stdio.h>
  2. #include <malloc.h>
  3. #include <stdbool.h>
  4. typedef struct Node {
  5. int data;
  6. struct Node* pNext;
  7. }NODE,*PNODE;
  8. typedef struct Stack {
  9. PNODE pTop;
  10. PNODE pBottom;
  11. }STACK,*PSTACK;
  12. void init(PSTACK pS);
  13. void push(PSTACK pS, int value);
  14. void traverse(PSTACK pS);
  15. bool pop(PSTACK, int*);
  16. void clear(PSTACK pS);
  17. int main(void) {
  18. STACK S;
  19. int popVal;
  20. init(&S);
  21. push(&S, 1);
  22. push(&S, 2);
  23. push(&S, 3);
  24. push(&S, 4);
  25. push(&S, 5);
  26. traverse(&S);
  27. if (pop(&S, &popVal)) {
  28. printf("³öÕ»³É¹¦£¬³öÕ»µÄÔªËØΪ%d\n", popVal);
  29. }
  30. else {
  31. printf("³öջʧ°Ü\n");
  32. }
  33. traverse(&S);
  34. clear(&S);
  35. traverse(&S);
  36. }
  37. void init(PSTACK pS) {
  38. pS->pTop = (PNODE)malloc(sizeof(NODE));
  39. if (pS->pTop == NULL) {
  40. printf("Malloc is error.");
  41. exit(-1);
  42. }
  43. else {
  44. pS->pBottom = pS->pTop;
  45. pS->pTop->pNext = NULL;
  46. }
  47. }
  48. void push(PSTACK pS, int value) {
  49. PNODE pNew = (PNODE)malloc(sizeof(NODE));
  50. pNew->data = value;
  51. pNew->pNext = pS->pTop; //pS->
  52. pS->pTop = pNew;
  53. }
  54. bool pop(PSTACK pS, int* popValue) {
  55. if (pS->pBottom == pS->pTop) {
  56. return false;
  57. }
  58. else {
  59. PNODE pTmp = pS->pTop;
  60. *popValue = pTmp->data;
  61. pS->pTop = pS->pTop->pNext;
  62. free(pTmp);
  63. pTmp = NULL;
  64. return true;
  65. }
  66. }
  67. void clear(PSTACK pS) {
  68. if (pS->pBottom == pS->pTop) {
  69. return;
  70. }
  71. else {
  72. printf("ÕýÔÚÇå³ý...");
  73. PNODE p = pS->pTop;
  74. PNODE q = NULL;
  75. while (p != pS->pBottom) {
  76. q = p->pNext;
  77. free(p);
  78. p = q;
  79. }
  80. pS->pTop = pS->pBottom;
  81. printf("Çå³ýÍê³É");
  82. }
  83. }
  84. void traverse(PSTACK pS) {
  85. PNODE p = pS->pTop;
  86. while (p->pNext != NULL) {
  87. printf("%d\n", p->data);
  88. p = p->pNext;
  89. }
  90. }

2.4.2栈应用

函数调用
中断
表达式求值
走迷宫
内存分配
缓冲处理

2.4.3队列

定义:一种可以实现“先进先出”的存储结构
分类:链式队列、静态队列
静态队列通常都必须是循环队列:

  • 静态队列为什么必须是循环队列
  • 循环队列需要几个参数来确定
  • 循环队列各个参数的含义
  • 循环队列入队伪算法讲解
  • 循环队列出队伪算法讲解
  • 如何判断循环队列是否为空
  • 如何判断循环队列是否已满