1 线性表的顺序实现
创建的新项目是cpp类型哦!
1.1 初始化
1.1.1 静态分配
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define MaxSize 10 //定义顺序表的长度
typedef struct {
int data[MaxSize];//用静态的数组存放元素!
int length;
}SqList;
//相当于python中的类,这个类有一个属性是 长度
//基本操作--初始化一个顺序表
void InitList(SqList& L) {
for (int i = 0; i < MaxSize; i++) {
L.data[i] = 0;
}//初始化每一个值为0
L.length = 0;
}
//主函数
int main() {
SqList L;//创建一个顺序表
InitList(L);//初始化一个顺序表!!!
return 0;
}
脏数据!
1.1.2 动态分配
1.2 基本操作【基于静态分配】
1.2.1 插入
1.2.2 删除操作
1.2.3 查找
【1】按位查找
静态分配:
动态分配:
注意指针!!!
【2】按值查找
数据是结构类型的时候比较不能用==
c语言程序设计!
2 线性表的链式表示-单链表
2.1 单链表的定义
用代码实现,带头结点/不带头结点,一般使用带头结点
代码实现:
【1】长一点的写法
【2】
2.2 初始化
2.2.1 不带头结点
2.2.2 带头结点
头结点不存储数据,
不带头结点那么这个头指针指向的就是实际用于存放数据的结点
而带头结点 这个头指针指向的是头结点 这个结点不存放数据,这个头结点之后的下一个结点才会用于存放数据!!!
2.3 按位序插入
2.3.1 带头结点
当i=1时
2.3.2 不带头指针
要对第一个结点做单独的处理!
2.4 给定结点在结点之后插入
时间复杂度o(1)
2.5 给定结点之前插入【前插】
2.5.1 方法一:传入头指针
o(n)
利用头阶段找到给定节点的前区结点!
2.5.2 方法二:偷天换日
时间复杂度0(1)
2.6 按位序删除
平均:o(n)
2.7 删除给定结点
偷天换日
如果p是最后一个结点的话:【只能采用方法一来弄!】
2.8 查找
2.8.1 按位查找
平均时间复杂度:o(n) 顺序表的按位置查找
可以封装起来,在插入和删除里进行调用!!
2.8.2 按值查找
o(n)
2.9 表的长度
2.10 建立单链表
2.10.1 尾插法建立
这样的问题是每次都要遍历到找到最后一个元素,那么时间复杂度就是0+1+2+3+.....+(n-1)这样的话时间复杂度就是o(n^2)
太高了,引入尾指针!
9999就是一个特殊的出口
时间复杂度就是o(n)
2.10.2 头插法
写代码的时候 去掉的那句写上就是好习惯!!!
头插法最后得到的是逆序的链表!
2.11 代码总结!!!!!!!!!!!
/带头结点!!
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <malloc.h>
typedef struct LNode {
int data;
struct LNode *next; //说明next是一个指针指向的元素类型是LNode
}LNode,*LinkList;
//初始化一个单链表带头结点
bool InitList(LinkList& L) {
L = (LNode*)malloc(sizeof(LNode));//创建一个头指针
//mallo函数返回的实际是一个无类型指针,必须在其前面加上指针类型强制转换才可以使用
//指针自身 = (指针类型 * )malloc(sizeof(指针类型) * 数据数量)
if (L == NULL) {
return false;
}
L->next = NULL;//头结点后面还没有元素
return true;
};
bool PrintLink(LinkList L) {
LNode* p;//创建一个p指针指向的数据类型是LNode
p = L->next;//刚开始p指向的是头结点的下一个结点
if (p== NULL) {//说明是空的
printf("The Link is empty\n");
return false;
};
while (p != NULL) {
printf("%d-->", p->data);
p = p->next;
};
return true;
}
//插入按位序插入
bool ListInsert(LinkList &L, int i, int a) {
//在第i个位置插入元素e
if (i < 1) {
return false;
};
LNode* p;
p = L;
int j = 0;
//插入就要找到前后的(i-1)前后的
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}//p表示的是i-2位置上的
if (p == NULL) {
//说明输入的i是不合法的!
printf("输入的i是不合法的");
return false;
};
//找到结点之后就可以进行插入了
//先申请空间存放e
LNode *s = (LNode*)malloc(sizeof(LNode));
if (s == NULL) {
printf("申请内存失败!");
return false;
}
s->data = a;
s->next = p->next;
p->next = s;
return true;
};
//在给定结点 后插
bool InsertNextNode(LNode* p, int a) {
//传入一个结点 和要插入的元素a
if (p == NULL) {
//说明插入为空
return false;
}
//这个结点已经找到了 直接进行插入就ok
LNode* s = (LNode*)malloc(sizeof(LNode));
if (s == NULL) {
return false;
}
s->next = p->next;
s->data = a;
p->next = s;
return 1;
}
//在给定节点前方插入元素方法1,需要传入头节点哦
bool InsertPriorNode1(LinkList L ,LNode* p,int a) {
return 0;
}
//在给定节点前方插入元素方法1,偷天换日
bool InsertPriorNode2(LNode* p, int a) {
LNode* s = (LNode*)malloc(sizeof(LNode));
s->next = p->next;
p->next = s;
s->data = p->data;
p->data = a;
//先建立连接然后写入数值哦
return true;
}
//按位序删除元素
bool ListDelete(LinkList& L, int i,int &e) {//e用于存放删除的值,由于要在外面显现所以要加上&
LNode* s;
s = L; //头节点的次序是0而且不存数据
if (i < 1) {
return false;
}
int j = 0;
//找到要删除的元素(i-1)前面的那个结点(i-2)即可
while (j < i-1) {
s = s->next;
j++;
}
LNode* q;
q = s->next;//q指向的是要删除的那个结点
e = q->data;
s->next = q->next;
free(q);
return true;
}
//按位查找元素【返回第i个位置的元素的值】
LNode* GetElem(LinkList L, int i) {
LNode* p;//创建一个指针
int j = 0;
p = L;//p指向头指针
while (p != NULL && j < i) {
p = p->next;
j++;
}
return p;
}
//按值查找
LNode* LocateElem(LinkList L, int e) {
LNode* p;
p = L;
int j = 0;
while (p != NULL&&p->data!=e) {
p = p->next;
j++;
}
return p;
}
//头插法建立单链表、
LinkList CreateList_head(LinkList& L) {
int x;
L = (LNode*)malloc(sizeof(LNode));
L->next = NULL;
LNode* s;
scanf("%d", &x);
while (x != 9999) {
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s;
scanf("%d", &x);
}
return L;
}
//尾插法建立单链表
LinkList CreateList_Tail(LinkList& L) {
L = (LNode*)malloc(sizeof(LNode));//创建头结点
LNode* s, * r = L;//当前结点和尾结点都指向头结点!
int y;
scanf("%d", &y);
while (y != 9999) {
s = (LNode*)malloc(sizeof(LNode));
s->data = y;
r->next = s;
r = s;
scanf("%d", &y);
}
r->next = NULL;
return L;
}
int main() {
LinkList L;//创建一个链表
InitList(L);//初始化链表
PrintLink(L);
printf("\n");
//ListInsert(L, 1, 1);//在第一个位置插入1
//ListInsert(L, 2, 2);//在第二个位置插入2
//PrintLink(L);
//printf("\n");
//int e = -1;
//ListDelete(L, 1,e);
//printf("删除的元素是%d\n", e);
//PrintLink(L);
//printf("\n");
printf("头插法建立单链表,输入值(9999结束)\n");
L = CreateList_head(L);
PrintLink(L);
printf("\n");
printf("尾插法建立单链表,输入值(9999结束)\n");
L = CreateList_Tail(L);
PrintLink(L);
return 0;
}
3 顺序表的链式表示-双链表
3.1 初始化
3.2 插入--后插
更严谨一点:
修改指针的顺序一定要先后面再前面
3.3 删除
3.4 销毁
3.5 遍历
注意指针修改的顺序!!!
注意边界的情况!!!
4 循环单链表
4.1 初始化
在删除的时候找不到前驱结点
找到最后一个结点
L指针放在表尾的时候就会 自己指向的是尾结点,下一个是头结点,当应用场景是要频繁的使用头结点和尾结点的时候,就把指针放在最后!
5 循环双链表
插入:
删除:
循环双链表不用考虑最后一盒结点
6 静态链表
初始化:
用数组存放,书本上的写法后面:
基本操作:
初始化:
查找某个位序的节点时间复杂度o(n)
插入:
空闲标记成-2
尽管是一整片连续的区域,但是各个在逻辑上相邻的元素在物理上也可以不相邻!
先后关系是通过游标实现的!
文件分配表FAT就是静态链表!
7 链表和顺序表比较
奶茶店排队取号
查询操作比较多,课堂点名