1.顺序表、单链表(基础数据结构)

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) 时间复杂度表示的规则:

  1. 取最高指数项 n^2 + n
  2. 去掉系数 for(int i = 0; i < n/2; ++i)
  3. 去掉常数

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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值