数据结构(1):线性表

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 链表和顺序表比较

奶茶店排队取号

查询操作比较多,课堂点名

相关推荐
Dong雨1 小时前
六大排序算法:插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序
数据结构·算法·排序算法
茶猫_2 小时前
力扣面试题 39 - 三步问题 C语言解法
c语言·数据结构·算法·leetcode·职场和发展
初学者丶一起加油2 小时前
C语言基础:指针(数组指针与指针数组)
linux·c语言·开发语言·数据结构·c++·算法·visual studio
半盏茶香4 小时前
C语言勘破之路-最终篇 —— 预处理(上)
c语言·开发语言·数据结构·c++·算法
2401_858286114 小时前
118.【C语言】数据结构之排序(堆排序和冒泡排序)
c语言·数据结构·算法
没事就去码4 小时前
RBTree(红黑树)
数据结构·c++
就爱学编程4 小时前
重生之我在异世界学编程之数据结构与算法:单链表篇
数据结构·算法·链表
CSCN新手听安10 小时前
list的常用操作
数据结构·list
梅茜Mercy11 小时前
数据结构:链表(经典算法例题)详解
数据结构·链表
青春男大12 小时前
java栈--数据结构
java·开发语言·数据结构·学习·eclipse