学习进度追踪【0321 - 0328】
1. M:函数的四种特性 & 函数图像 102M;
2. C:指针 - 函数 - 递归调用 - 全局变量 93M;
3. LC:周竞赛题回顾,不多于93M;
顺序表的特点
1,随机访问,类似于哈希存储,能够通过数据类型占用字节数和元素位序直接访问对应内存地址的值;
2,存储密度高,相对于链表存储方式的一句废话,链表的结点除了存储元素,还需要存储元素的指针;
3,拓展容量不方便,初始空间不足,想要传递更多元素只能放弃治疗,动态分配内存需要全员移位,时间复杂度为O(N),性能不优;
4,插入删除元素不方便,插入需要从右到左移动该元素之后的所有元素,删除操作需要从左到右移动该元素之后的所有元素,时间复杂度为O(N)
顺序表-初始化和动态分配
/*-使用malloc & free实现为线性表动态分配内存空间-*/
#include <stdio.h>
#include <stdlib.h>
#define InitSize 10
// 定义线性表的数据结构
typedef struct {
int* data; // 动态分配数组的指针
int Maxsize; // 数组的最大长度
int length; // 数组的当前长度
}SqList;
// 初始化线性表
void InitList(SqList& L) {
// 用malloc 函数申请一片连续的内存空间
L.data = (int*)malloc(InitSize * sizeof(int)); // 强制类型转换
L.length = 0;
L.Maxsize = InitSize;
}
// 增加线性表长度
void IncreaseSize(SqList &L, int len) {
int *p = L.data;
L.data = (int*)malloc((L.Maxsize + len) * sizeof(int));
for (int i = 0; i < L.length; i++) {
L.data[i] = p[i]; // 将数据复制到新区域
}
L.Maxsize = L.Maxsize + len; // 顺序表最大长度增减 len(长度)
free(p); // 释放内存空间
}
// 主函数,分别调用
int main(void)
{
SqList L;
InitList(L);
IncreaseSize(L, 5);
return 0;
}
//
顺序表—-插入和删除操作
/*顺序表的按位查找*/
#define MaxSize 10 /*定义最大长度*/
typedef struct {
ElemType data[MaxSize]; /*用静态的数组存放数据元素---静态分配*/
int length; /*顺序表的当前长度*/
} SqList; /*顺序表的类型定义---静态分配方式*/
ElemType GetElem(SqList L, int i){
return L.data[i - 1]; /*为增强健壮性可以在此判断输入值是否合法*/
}
/*顺序表的按位查找动态分配方式*/
#define InitSize 10 /*顺序表的初始长度*/
typedef struct{
ElemType *data; /*指明动态分配数组的指针*/
int MaxSize; /*顺序表的最大容量*/
int length; /*顺序表的当前长度*/
} SeqList; /*顺序表的类型定义---动态分配方式*/
ElemType GetElem(SeqList L, int i){
return L.data[i - 1]; /*即使定义为数组,仍然可以用下标的方式访问*/
}
/*顺序表的按值查找*/
typedef struct {
int * data; /*指定动态分配数组的指针*/
int MaxSize; /*顺序表的最大容量*/
int length; /*顺序表的当前长度*/
}
/*在顺序表L中查找第一个值为e的元素,并返回其位序*/
int LocateElem(SeqList L, int e){
for (int i = 0; i < L.length; i++){
if (L.data[i] == e) /*基本数据类型:int, char, double, float等都可以用运算符“==”比较*/
return i + 1; /*返回值是该元素的位序,因此值加一*/
}
return 0;
}
int main(void)
{
LocateElem(L, 9); /*调用该函数,查找目标元素*/
return 0;
}
/*复杂度分析:
1, 最好情况,待查找元素就在表头,那么一次循环就可以找到
2,最坏情况,待查找元素就在表尾或者不在数组之中,那么需要查找n次,n为该数组的长度
3, 平均情况,概率为: 1/n, 总共执行 (1/2) *[n(n + 1)] * ( 1/ n) = 1/2 * (n + 1) 近似于n
*/
求解问题集
解引用地址运算符—-*和读取地址运算符—-&的意义
链表
概念上与线性表的比较
链表的存储密度低,除数据域之外还有指针域;
顺序表连续存储,更改容量需要付出n+m的空间,非常不便;
链表更改数据只需要修改指针,数据可以不连续存放,但失去随机存储的特性,需要从头到尾遍历;
对链表定义的理解
struct LNode{ /*建立一个结构体*/
ElemType data; /*定义一个数据域,用来存放数据元素*/
struct LNode *next; /*对数据域本身套娃,可以理解为重定义数据域,改为指针域,但原来的位置不变,可能不均等的二分*/
};
typedef struct LNode LNode; /*使用typedef结构体重命名的能力,对结构体重新命名*/
typedef struct LNode *LinkList; /*生成俩变量,一个存储数据,一个存储指针*/
LNode * L; /*声明一个指向单链表第一个结点的指针*/
LinkList * L; /*声明一个指向单链表第一个结点的指针*/
/*--要表示一个单链表时,只需要声明一个头指针L,指向单链表第一个结点--*/
用代码定义一个链表
/*---用代码定义一个不带头结点的链表---*/
typedef struct LNode{
ElemType datif
struct LNode *next;
} LNode, *LinkList;
定义一个不带头结点的单链表
#include <stdbool.h>
/*初始化一个空的单链表*/
bool InitList(LinkList &L){
if (L = NULL); /*空表,暂时没有数据,也是为了清除脏数据*/
return true; /*程序健壮性,建立空链表成功则进行回报*/
else
return false;
}
void test(){
LinkList L; /*声明一个指向单链表的指针*/
/*初始化一个空表*/
InitList(L);
/*其他代码*/
}
定义一个带头结点的单链表
/*-----定义一个带头结点的单链表-------*/
typedef struct LNode{
ElemType data;
struct LNode *next;
} LNode, *LinkList;
bool InitList(LinkList &L){
L = (LNode*)malloc(sizeof(LNode));
if (L == NULL)
return false;
L->next = NULL;
return true;
}
void test(){
LinkList L; /*声明一个指向单链表的指针*/
/*初始化一个空表*/
InitList(L);
/*后续代码*/
}
/*判断是否为空*/
bool Empty(Linklist L){
if(L->next == NULL)
return true;
else
return false;
}
链表的插入
/*---------------线性表的插入----------------*/
#include <stdio.h>
#include <stdbool.h>
typdef struct LNode{
ElemType data;
struct LNode *next;
}LNode, LinkList;
bool ListInsert(LinkList &L, int i, ElemType e){
if (i < 1) /*判断位序是否合法*/
return false;
LNode *p; /*指针p指向当前扫描到的结点*/
int j = 0; /*当前p指向的是第几个结点,是实指还是初始化*/
p = L;
while (p != NULL && j < i - 1){ /*循环找到第i-1个结点,链表不为空,且最大搜寻长度为i-1*/
p = p->next; /**/
j++;
}
if (p == NULL)
return false;
LNode *s = (LNode*)malloc(sizeof(LNode)); /*创造了一个临时变量存储待插入值*/
s->data = e; /*将值导入临时空间*/
s->next = p->next; /将后一个结点的指针先指向临时空间/
p->next = s; /*头结点的下一个空间指针指向临时空间*/
return true;
}