1.数据结构
数据结构研究的是数据存储的问题,数据结构=个体的存储+个体的关系存储。
算法 = 对存储数据的操作
衡量算法的标准:
- 时间复杂度:程序执行的次数,而非时间
- 空间复杂度:程序执行过程中所占用的最大内存
- 难易程度
- 健壮性
2.线性结构
2.1 定义
2.2 分类
2.2.1连续存储(数组)
看懂一个程序分为三步:流程、每个语句的功能、试数。
参数,长度,有效元素的个数
(1)用C实现面向对象数组:(此处代码省略了数组增长因子Inversion)

#include <stdio.h>#include <malloc.h>#include <stdlib.h> //包含exit函数struct Array{int* pArr;//数组地址int len;//数组长度int ctn;//数组有效元素个数};void init(struct Array*,int length);//数组初始化bool is_empty(struct Array*);//数组为空判断bool is_full(struct Array*);//数组是否满了bool show_array(struct Array*);//数组打印操作bool add_array(struct Array*,int value);//数组添加元素操作int main(){struct Array array;init(&array, 10);add_array(&array, 4);show_array(&array);add_array(&array, 5);show_array(&array);}bool is_full(struct Array* array){if (array->ctn > array->len){return true;}else{return false;}}bool add_array(struct Array* array, int value){if (is_full(array)){printf("数组已满\n");return false;}else{int index = array->ctn;array->pArr[index] = value;(array->ctn)++;return true;}}void init(struct Array* array, int length){array->pArr = (int*)malloc(sizeof(int)*length);if (NULL == array->pArr){printf("未申请到内存空间\n");exit(-1);//退出函数}else{array->len = length;array->ctn = 0;}return;}bool is_empty(struct Array* array){if (0 == array->ctn){return true;}else{return false;}}bool show_array(struct Array* array){if (!is_empty(array)){for (int i = 0; i < array->ctn; i++){printf("%d\n", array->pArr[i]);}printf("\n");return true;}else{printf("数组为空!\n");return false;}}
(2)排序
#include <stdio.h>#include <malloc.h>#include <stdlib.h> //包含exit函数struct Array{int* pArr;//数组地址int len;//数组长度int ctn;//数组有效元素个数};void init(struct Array*,int length);bool is_empty(struct Array*);bool is_full(struct Array*);bool show_array(struct Array*);bool add_array(struct Array*,int value);bool insert_array(struct Array*, int pos, int val);void sort_array(struct Array*);int main(){struct Array array;init(&array, 5);add_array(&array, 4);show_array(&array);add_array(&array, 5);show_array(&array);insert_array(&array, 1, 3);show_array(&array);v}bool is_full(struct Array* array){if (array->ctn > array->len){return true;}else{return false;}}bool insert_array(struct Array* parray, int pos, int val){if (pos<=parray->ctn){int index = parray->ctn - 1;for (int i = index; i > pos-1; --i){parray->pArr[index+1] = parray->pArr[index];}parray->pArr[pos-1] = val;parray->ctn++;return true;}else{printf("超出数组长度%d\n", parray->len);return false;}}//冒泡排序法//两两比较,最外围循环递减,内层循环递增void sort_array(struct Array* parray){for (int j = parray->ctn - 1; j >0 ; j--){for (int i = 0; i < j; i++){if (parray->pArr[i] > parray->pArr[i + 1]) {int t = parray->pArr[i];parray->pArr[i] = parray->pArr[i + 1];parray->pArr[i + 1] = t;}}}}bool add_array(struct Array* array, int value){if (is_full(array)){printf("数组已满\n");return false;}else{int index = array->ctn;array->pArr[index] = value;(array->ctn)++;return true;}}void init(struct Array* array, int length){array->pArr = (int*)malloc(sizeof(struct Array)*length);if (NULL == array->pArr){printf("未申请到内存空间\n");exit(-1);//退出函数}else{array->len = length;array->ctn = 0;}return;}bool is_empty(struct Array* array){if (0 == array->ctn){return true;}else{return false;}}bool show_array(struct Array* array){if (!is_empty(array)){for (int i = 0; i < array->ctn; i++){printf("%d\n", array->pArr[i]);}printf("\n");return true;}else{printf("数组为空!\n");return false;}}
(3)小知识
typedef 重命名:
#include <stdio.h>#include <string>using namespace std;typedef struct Student // Typedef重命名{int Weight;}ST;//ST等价于struct Studentint main(void){ST st;st.Weight = 120;printf("Name = %d\n",st.Weight);}
#include <stdio.h>#include <string>using namespace std;typedef struct Student // Typedef重命名{int Weight;}* PST;//PST等价于struct Student *;int main(void){struct Student st;st.Weight = 120;PST pst = &st;pst->Weight = 124;printf("Name = %d\n",st.Weight);}
//二合一#include <stdio.h>#include <string>using namespace std;typedef struct Student // Typedef重命名{int Weight;}* PST,ST;int main(void){ST st;st.Weight = 120;PST pst = &st;pst->Weight = 124;printf("Name = %d\n",st.Weight);}
2.2.2离散存储(链表)
(1)链表的重要性:树,图的本质都是链表
(2)定义
n个节点离散分配
彼此通过指针相连
每个节点只有一个前驱节点,每个节点只有一个后续节点
首节点没有前驱节点 尾节点没有后续节点
专业术语:
头节点—首节点————-尾节点
首节点:第一个有效节点
尾节点:最后一个有效节点
头节点:
头节点的数据类型和首节点类型一样
第一个有效节点之前的那个节点
头节点并不存放有效数据
加头节点的目的是为了方便对链表的操作
头指针:指向头节点的指针变量
尾指针:指向尾节点的指针变量
如果希望通过一个函数来对链表进行处理,我们至少需要接受链表的哪些信息:一个参数,头指针
因为我们通过头指针可以推算出链表的其他所有信息
struct Node
{
int data;数据域
struct Node * pNext;指针域
};
(3)分类
单链表
双链表:每个节点有两个指针域
循环链表:
能通过任何一个节点找到其他所有的节点
非循环链表
(4)算法
狭义的算法是与数据存储方式密切相关的,广义的算法与数据存储方式无关。
泛型:利用某种技术达到的效果就是:不同的存储方式执行的操作是相同的。
遍历
查找
清空
销毁
求长度
排序
插入:r=p->pNext;p->pNext = q;q->pNext = r;
(5)链表的优缺点
2.3 链表的创建及遍历
创建
#include <stdio.h>typedef struct Node {int data;//Data Fieldstruct Node* pNext;// Point Field}NODE,*PNODE;void TraverseList(PNODE);PNODE CreateList();int main(void) {PNODE pHead = NULL;pHead = CreateList();TraverseList(pHead);}PNODE CreateList() {int len;//Node Ctnint value;//Node ValuePNODE pHead = (PNODE)malloc(sizeof(NODE));PNODE pTail = pHead;pTail->pNext = NULL;printf("Please input node number:");scanf_s("%d", &len);if (len > 0) {for (int i = 0; i < len; i++){printf("Please input value of %d", i + 1);scanf_s("%d", &value);PNODE pNext = (PNODE)malloc(sizeof(NODE));pNext->data = value;pTail->pNext = pNext;pTail = pNext;pNext->pNext = NULL;//The end node pNext is NULL.}}else {printf("Please input number more than zero.");}return pHead;}void TraverseList(PNODE pHead) {PNODE pTemp = pHead->pNext;while (NULL != pTemp) {printf("%d\n", pTemp->data);pTemp = pTemp->pNext;}}
遍历
临时结点p
#include <stdio.h>typedef struct Node {int data;//Data Fieldstruct Node* pNext;// Point Field}NODE,*PNODE;void TraverseList(PNODE);PNODE CreateList();int main(void) {PNODE pHead = NULL;pHead = CreateList();TraverseList(pHead);}PNODE CreateList() {int len;//Node Ctnint value;//Node ValuePNODE pHead = (PNODE)malloc(sizeof(NODE));PNODE pTail = pHead;pTail->pNext = NULL;printf("Please input node number:");scanf_s("%d", &len);if (len > 0) {for (int i = 0; i < len; i++){printf("Please input value of %d", i + 1);scanf_s("%d", &value);PNODE pNext = (PNODE)malloc(sizeof(NODE));pNext->data = value;pTail->pNext = pNext;pTail = pNext;pNext->pNext = NULL;//The end node pNext is NULL.}}else {printf("Please input number more than zero.");}return pHead;}void TraverseList(PNODE pHead) {PNODE pTemp = pHead->pNext;while (NULL != pTemp) {printf("%d\n", pTemp->data);pTemp = pTemp->pNext;}}
2.4 应用
2.4.1栈实现
栈:先进后出,压栈出栈。
#include <stdio.h>#include <malloc.h>#include <stdbool.h>typedef struct Node {int data;struct Node* pNext;}NODE,*PNODE;typedef struct Stack {PNODE pTop;PNODE pBottom;}STACK,*PSTACK;void init(PSTACK pS);void push(PSTACK pS, int value);void traverse(PSTACK pS);bool pop(PSTACK, int*);void clear(PSTACK pS);int main(void) {STACK S;int popVal;init(&S);push(&S, 1);push(&S, 2);push(&S, 3);push(&S, 4);push(&S, 5);traverse(&S);if (pop(&S, &popVal)) {printf("³öÕ»³É¹¦£¬³öÕ»µÄÔªËØÎª%d\n", popVal);}else {printf("³öջʧ°Ü\n");}traverse(&S);clear(&S);traverse(&S);}void init(PSTACK pS) {pS->pTop = (PNODE)malloc(sizeof(NODE));if (pS->pTop == NULL) {printf("Malloc is error.");exit(-1);}else {pS->pBottom = pS->pTop;pS->pTop->pNext = NULL;}}void push(PSTACK pS, int value) {PNODE pNew = (PNODE)malloc(sizeof(NODE));pNew->data = value;pNew->pNext = pS->pTop; //pS->pS->pTop = pNew;}bool pop(PSTACK pS, int* popValue) {if (pS->pBottom == pS->pTop) {return false;}else {PNODE pTmp = pS->pTop;*popValue = pTmp->data;pS->pTop = pS->pTop->pNext;free(pTmp);pTmp = NULL;return true;}}void clear(PSTACK pS) {if (pS->pBottom == pS->pTop) {return;}else {printf("ÕýÔÚÇå³ý...");PNODE p = pS->pTop;PNODE q = NULL;while (p != pS->pBottom) {q = p->pNext;free(p);p = q;}pS->pTop = pS->pBottom;printf("Çå³ýÍê³É");}}void traverse(PSTACK pS) {PNODE p = pS->pTop;while (p->pNext != NULL) {printf("%d\n", p->data);p = p->pNext;}}
2.4.2栈应用
2.4.3队列
定义:一种可以实现“先进先出”的存储结构
分类:链式队列、静态队列
静态队列通常都必须是循环队列:
- 静态队列为什么必须是循环队列
- 循环队列需要几个参数来确定
- 循环队列各个参数的含义
- 循环队列入队伪算法讲解
- 循环队列出队伪算法讲解
- 如何判断循环队列是否为空
- 如何判断循环队列是否已满
