1.vs 基础使用
使用“解决方法” 来管理所有的工程。
2.算法的评价
2.1时间复杂度
时间复杂度是算法的与问题规模大小的一个函数。Markdown将文本转换为 HTML。
从算法中抽取一个基本操作,以基本操作执行的次数来衡量算法的效率
1) O(1)
没有循环,或者循环的次数与问题的规模没有关系 – 循环是的次数是一个常数
2) O(n)
算法肯定是有循环或者递归, 而且这种循环或递归执行的次数与问题规模相等(控制循环或者递归的变量是以+1,或者 -1的方式趋于退出条件发生的)。
3) O(n^2)
两个O(n)相乘。 循环嵌套
4) O(logn)
算法肯定是有循环或者递归, 而且这种循环或递归执行的次数与问题规模有关系,控制循环或递归的变量是以*2或者/2的方式趋于结束的。 log2(n)
5) 时间复杂度表示的规则:
- 取最高指数项 n^2 + n
- 去掉系数 for(int i = 0; i < n/2; ++i)
- 去掉常数
2.2空间复杂度
算法执行过程中所需要的额外的(除了存储计算的数据本身)存储空间与问题规模n的函数关系。
计算方法:
算法实现过程中有没有使用malloc或者new 申请与问题规模n相关的空间
算法有没有使用递归,并且递归的次数与问题规模n相关 一个函数开辟的堆栈空间比较大
3.数据结构的基础概念
什么是数据结构:
相互之间存在一种或多种特定关系的数据元素的集合。
关系: 集合 线性关系 树形关系 图形关系
要学习的数据结构:
数据之间的存储关系如何用C语言表示
针对于一个结构中存储的数据有相对应的操作方法。
4.顺序表
线性关系:
顺序结构 顺序在逻辑上是连续的,在物理存储上也是连续的
链式结构 在逻辑上是连续的,在物理存储上是不连续的
4.1顺序表的结构
顺序表结构中需要的成员:
1、用于存储数据元素的空间位置
2、当前已存储的数据元素的个数 – 记录存储数据的位置
3、空间能够存储的元素的总量 – 扩容
4、顺序表存储数据元素时,必须从空间的起始位置开始连续存储
4.2顺序表的C语言结构设计
#define DEFAULTSIZE 10
typedef int ElemType;
typedef struct SqList
{
ElemType *data; // 指向用于存储ElemType类型的堆区空间的指针
int length; // 长度: 以存储的属于元素的个数
int size; // 空间的大小,记录的是能够存储的元素个数
}SqList;
typedef bool(*Compare)(ElemType, ElemType); // bool (ElemType,
ElemType)* Compare
// 初始化
void InitSqList(SqList *sq_list, int init_size);
// 销毁
void DestroySqList(SqList *sq_list);
// 插入
/*
1、头插法
2、尾插法
3、按位置插入
*/
bool InsertSqListHead(SqList *sq_list, ElemType value);
bool InsertSqListRear(SqList *sq_list, ElemType value);
bool InsertSqListPos(SqList *sq_list, ElemType value, int pos);
// 删除
/*
1、头删法
2、尾删法
3、按位置删
4、按值删除
*/
bool DeleteSqListHead(SqList *sq_list);
bool DeleteSqListRear(SqList *sq_list);
bool DeleteSqListPos(SqList *sq_list, int pos);
bool DeleteSqListValue(SqList *sq_list, ElemType value);
// 查找 : 返回位置(下标):取值范围 0 -- length-1
int FindSqList(SqList *sq_list, ElemType value, Compare fun);
// 判空
bool Empty(SqList *sq_list);
// 判满
bool Full(SqList *sq_list);
void Show(SqList *sq_list);
4.3方法实现
// 如何实现一个函数不能被外部调用
static bool AppendSpace(SqList *sq_list)
{
int new_size = sq_list->size * 2;
ElemType *new_space = (ElemType *)malloc(sizeof(ElemType) *
new_size);
if (new_space == nullptr) return false;
// 挪数据: 将原始空间的数据挪动到新的空间中
for (int i = 0; i < sq_list->size; ++i)
{
new_space[i] = sq_list->data[i];
}
free(sq_list->data);
sq_list->data = new_space;
sq_list->size = new_size;
return true;
}
// 初始化
void InitSqList(SqList *sq_list, int init_size)
{
if (sq_list == nullptr) exit(0);
init_size = init_size > 0 ? init_size : DEFAULTSIZE;
sq_list->data = (ElemType *)malloc(init_size * sizeof(ElemType));
if (sq_list->data == nullptr) exit(0);
sq_list->length = 0;
sq_list->size = init_size;
}
// 销毁
void DestroySqList(SqList *sq_list)
{
if (sq_list == nullptr) exit(0);
free(sq_list->data);
sq_list->data = nullptr;
sq_list->length = sq_list->size = 0;
}
// 插入
/*
1、头插法 0
2、尾插法 length
3、按位置插入 pos
*/
bool InsertSqListHead(SqList *sq_list, ElemType value)
{
return InsertSqListPos(sq_list, value, 0);
}
bool InsertSqListRear(SqList *sq_list, ElemType value)
{
if (sq_list == nullptr) exit(0);
return InsertSqListPos(sq_list, value, sq_list->length); // 函数调
用过程: 先压参, 在调用
}
bool InsertSqListPos(SqList *sq_list, ElemType value, int pos)
{
if (sq_list == nullptr) exit(0);
if (pos < 0 || pos > sq_list->length)
{
printf("Insert Fail: Pos is error\n");
return false;
}
if (Full(sq_list))
{
if (!AppendSpace(sq_list)) // 扩容
{
printf("Insert Fail: Append Space Fail\n");
return false;
}
}
// 挪动pos位置及其之后的数据,统一向后挪动一个位置: 从length - 1向前挪动
for (int i = sq_list->length - 1; i >= pos; --i)
{
sq_list->data[i + 1] = sq_list->data[i];
}
sq_list->data[pos] = value;
sq_list->length++;
return true;
}
// 判满
bool Full(SqList *sq_list)
{
if (sq_list == nullptr) exit(0);
return sq_list->length == sq_list->size;
}
// 判空
bool Empty(SqList *sq_list)
{
if (sq_list == nullptr) exit(0);
return sq_list->length == 0;
}
void Show(SqList *sq_list)
{
if (sq_list == nullptr) exit(0);
printf("%p : ", sq_list->data);
for (int i = 0; i < sq_list->length; ++i)
{
printf("%d ", sq_list->data[i]);
}
printf("\n");
}
// 删除
/*
1、头删法
2、尾删法
3、按位置删
4、按值删除
*/
bool DeleteSqListHead(SqList *sq_list)
{
return DeleteSqListPos(sq_list, 0);
}
bool DeleteSqListRear(SqList *sq_list)
{
if (sq_list == nullptr) exit(0);
return DeleteSqListPos(sq_list, sq_list->length - 1);
}
bool DeleteSqListPos(SqList *sq_list, int pos)
{
if (sq_list == nullptr) exit(0);
if (pos < 0 || pos >= sq_list->length)
{
printf("Delete Fail: Pos is error\n");
return false;
}
if (Empty(sq_list))
{
printf("Delete Fail: SqList is Empty\n");
return false;
}
for (int i = pos; i < sq_list->length - 1; ++i)
{
sq_list->data[i] = sq_list->data[i + 1];
}
sq_list->length--;
return true;
}
// 删除顺序表中所有的value值: 时间复杂度为O(n), 空间复杂度为O(1)
bool DeleteSqListValue(SqList *sq_list, ElemType value)
{
if (sq_list == nullptr) exit(0);
int i = 0, j = 0;
for (; j < sq_list->length; ++j)
{
if (sq_list->data[j] != value)
{
sq_list->data[i] = sq_list->data[j];
i++;
}
}
sq_list->length = i;
return true;
}
int FindSqList(SqList *sq_list, ElemType value, Compare fun)
{
if (sq_list == nullptr) exit(0);
for (int i = 0; i < sq_list->length; ++i)
{
if (fun(value, sq_list->data[i]))
{
return i;
}
}
return -1;
}
5.单链表
单链表: 在逻辑上是连续的,在物理存储上是不连续的(每一个数据元素都占一个单独的位置), 只能够从头到尾遍历。
5.1单链表的结构申明
typedef int ElemType;
typedef struct Node
{
ElemType data; // 元素
struct Node *next; // 下一个结点的地址
}SNode, *LinkList;
5.2带头结点的单链表
typedef int ElemType;
typedef struct Node
{
union
{
int length;
ElemType data;
};
struct Node *next;
}HSNode, *HLinkList;
void InitHLinkList(HLinkList head);
void DestroyHLinkList(HLinkList head);
bool InsertHLinkListPos(HLinkList head, ElemType value, int pos);
ElemType FindOFIndex(HLinkList head, int index);
int Length(HLinkList head);
// 删除
bool DeleteHLinkListPos(HLinkList head, int pos);
// 判空
bool Empty(HLinkList head);
// 显示
void Show(HLinkList head);
#include "linklisthead.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
void InitHLinkList(HLinkList head)
{
if (head == nullptr) exit(0);
head->length = 0;
head->next = nullptr;
}
void DestroyHLinkList(HLinkList head)
{
if (head == nullptr) exit(0);
while (!Empty(head))
{
DeleteHLinkListHead(head);
}
}
bool InsertHLinkListPos(HLinkList head, ElemType value, int pos)
{
if (head == nullptr) exit(0);
if (pos < 0 || pos > Length(head))
{
printf("Insert Fail: Pos is error\n");
return false;
}
HLinkList p = head;
while (pos)
{
p = p->next;
pos--;
}
HLinkList new_node = (HLinkList)malloc(sizeof(HSNode));
if (new_node == nullptr)
{
printf("Insert Fail: Apply Node Fail\n");
return false;
}
new_node->data = value;
new_node->next = p->next;
p->next = new_node;
head->length++;
return true;
}
bool InsertHLinkListHead(HLinkList head, ElemType value)
{
return InsertHLinkListPos(head, value, 0);
}
bool InsertHLinkListRear(HLinkList head, ElemType value)
{
return InsertHLinkListPos(head, value, Length(head));
}
void Show(HLinkList head)
{
if (head == nullptr) exit(0);
HLinkList p = head->next;
while (p != nullptr)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
ElemType FindOFIndex(HLinkList head, int index)
{
if (head == nullptr) exit(0);
if (index < 0 || index >= Length(head)) throw "index error";
HLinkList p = head->next;
while (index)
{
p = p->next;
index--;
}
return p->data;
}
int Length(HLinkList head)
{
if (head == nullptr) exit(0);
return head->length;
}
// 删除
bool DeleteHLinkListPos(HLinkList head, int pos)
{
if (head == nullptr) exit(0);
if (pos < 0 || pos >= Length(head)) return false;
HLinkList p = head;
while (pos)
{
pos--;
p = p->next;
}
HLinkList q = p->next;
p->next = q->next;
free(q);
head->length--;
return true;
}
bool DeleteHLinkListHead(HLinkList head)
{
return DeleteHLinkListPos(head, 0);
}
bool DeleteHLinkListRear(HLinkList head)
{
return DeleteHLinkListPos(head, Length(head) - 1);
}
bool DeleteHLinkListValue(HLinkList head, ElemType value)
{
if (head == nullptr) exit(0);
HLinkList p = head;
HLinkList q = p->next;
while (q != nullptr)
{
if (q->data == value)
{
p->next = q->next;
free(q);
}
else
{
p = q;
}
q = p->next;
}
}
// 判空
bool Empty(HLinkList head)
{
if (head == nullptr) exit(0);
//return head->length == 0;
return head->next == nullptr;
}
5.3头指针实现单链表
typedef int ElemType;
typedef struct SNode
{
ElemType data; // 元素
struct Node *next; // 下一个结点的地址
}SNode, *LinkList;
void InitLinkList(LinkList *phead);
void DestroyLinkList(LinkList *phead);
bool InsertLinListPos(LinkList *phead, ElemType value, int pos);
bool InsertLinkListHead(LinkList *phead, ElemType value);
bool InsertLinkListRear(LinkList *phead, ElemType value);
int Length(LinkList *phead);
bool DeleteLinkListHead(LinkList *phead);
bool DeleteLinkListPos(LinkList *phead, int pos);
bool DeleteLinkListRear(LinkList *phead);
void Show(LinkList *phead);
bool Empty(LinkList *phead);
#include "linklist.h"
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
void InitLinkList(LinkList *phead)
{
if (phead == nullptr) exit(0);
*phead = nullptr;
}
static LinkList ApplyNode(ElemType value, LinkList next)
{
LinkList new_node = (LinkList)malloc(sizeof(SNode));
if (new_node == nullptr) return nullptr;
new_node->data = value;
new_node->next = next;
return new_node;
}
bool InsertLinkListHead(LinkList *phead, ElemType value)
{
if (phead == nullptr) exit(0);
LinkList new_node = ApplyNode(value, *phead);
if (new_node == nullptr) return false;
*phead = new_node;
return true;
}
int Length(LinkList *phead)
{
if (phead == nullptr) exit(0);
LinkList p = *phead;
int num = 0;
while (p != nullptr)
{
p = p->next;
num++;
}
return num;
}
bool InsertLinListPos(LinkList *phead, ElemType value, int pos)
{
if (phead == nullptr) exit(0);
if (pos < 0 || pos > Length(phead)) return false;
if (pos == 0) return InsertLinkListHead(phead, value);
LinkList p = *phead;
while (pos > 1)
{
p = p->next;
pos--;
}
LinkList new_node = ApplyNode(value, p->next);
if (new_node == nullptr) return false;
p->next = new_node;
return true;
}
bool InsertLinkListRear(LinkList *phead, ElemType value)
{
return InsertLinListPos(phead, value, Length(phead));
}
void Show(LinkList *phead)
{
if (phead == nullptr) exit(0);
LinkList p = *phead;
while (p != nullptr)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
bool DeleteLinkListHead(LinkList *phead)
{
if (phead == nullptr) exit(0);
if (Empty(phead)) return false;
LinkList p = *phead;
*phead = p->next;
free(p);
return true;
}
bool DeleteLinkListPos(LinkList *phead, int pos)
{
if (phead == nullptr) exit(0);
if (pos < 0 || pos >= Length(phead)) return false;
if (pos == 0) return DeleteLinkListHead(phead);
LinkList p = *phead;
while (pos > 1)
{
p = p->next;
pos--;
}
LinkList q = p->next;
p->next = q->next;
free(q);
return true;
}
bool DeleteLinkListRear(LinkList *phead)
{
return DeleteLinkListPos(phead, Length(phead) - 1);
}
bool Empty(LinkList *phead)
{
if (phead == nullptr) exit(0);
return *phead == nullptr;
}
void DestroyLinkList(LinkList *phead)
{
if (phead == nullptr) exit(0);
while (!Empty(phead))
{
DeleteLinkListHead(phead);
}
}
6.单链表和顺序表的优缺点
顺序表:
优点:可以通过下标来直接访问数据,时间复杂度O(1)
简单,好想好理解
尾插和尾删不需要移动数据,时间复杂度是O(1)
缺点:插入和删除要移动数据,时间复杂度是O(n)
单链表:
优点:链式结构,插入删除不需要移动数据,只需要改变一下它指针的指向,时间复杂度为O(1)
缺点:不可以通过下标来直接访问,时间复杂度为O(n)