数据结构速成--Day01

本文深入探讨了数据结构中的顺序表,包括其逻辑结构、存储结构和操作。详细介绍了线性表的概念,如一对一的关系、插入和删除元素的规则。文章通过C语言代码展示了顺序表的插入和删除操作,并讲解了typedef关键字的作用。此外,还讨论了顺序表的创建、满判断、空判断、长度获取和清空等操作。最后,提到了链式存储结构,特别是无头单向链表的实现。
摘要由CSDN通过智能技术生成

数据结构深入学习Day01

一、数据结构相关
1.数据结构:数据的逻辑结构、存储结构及操作
2.数据元素:是数据的基本单位,由若干个基本项组成(数据项)
3.节点:数据元素就叫节点
4.数据关系:线性、层次(树)、网状(图)
5.存储结构:
顺序、链式、索引、散列
6.算法原则:有穷性(时间消耗)、可行性、消耗空间小、可读性、可维护性、移植性
二、线性表
一对一,每个节点最多有一个前驱一个后继。
首节点无前驱,尾节点无后继。
顺序表插入删除元素:
插入时从后往前替换
删除时从前往后替换

#include <stdio.h>

int last = 5;//全局变量,last的值时刻代表数组中有效元素的个数

//将数组中的有效元素打印输出
void showArray(int* p)
{
	int i;
	for(i = 0; i < last; i++)
	{
		printf("%d ",p[i]);
	}
	printf("\n");
}

//int post 插入的位置 第几个
//int x 插入的数据
void insertIntoA(int* p, int post, int x)
{
	//1.从有效元素位置下标--插入位置的下标整体向后移动一个位置 last-1 -- post-1
	int i;
	for(i = last-1; i >= post-1; i--)
		p[i+1] = p[i];
	//2.将新的数据插入
	p[post-1] = x;//post-1 因为第post个位置,对应的下标是post-1
	//3.有效元素的个数+1  last++
	last++;
}
//删除指定位置的数据
void deleteFromA(int* p, int post)
{
	//1.将从删除位置的后一个位置的下标--最后一个有效元素,整体向前移动一个位置
	//post -- last-1
	int i;
	for(i = post; i <= last-1; i++)
	  p[i-1] = p[i];
	//2.有效元素个数-1
	last--;
}

int main(int argc, const char *argv[])
{
	int a[100] = {11,22,33,44,55};
	showArray(a);
	//增加,在第3个位置,插入一个数1000
	insertIntoA(a, 6, 1000);
	showArray(a);//11 22 1000 33 44 55
	deleteFromA(a, 6);//删除第3个位置的数据
	showArray(a);//11 22 33 44 55
	
	return 0;
}	

三、typedef关键字(类型重定义,增强可移植性)
Typedef int ZZZ;
ZZZ a=10;//相当于int a=10;

typedef int size_t;
	

	size_t a = 10; //等价于int a = 10
	
	void *malloc(size_t size);//size_t 类型重定义

	struct student
	{
		char name[20];//成员变量
		int age;
		int score;
	};//一定要有分号

四、顺序表:结构体结合
顺序表操作:
(1)创建空顺序表
(2)向指定位置插入元素
(3)判断顺序表是否为满
(4)删除指定位置元素
(5)判断顺序表是否为空
(6)求表长
(7)清空顺序表
(8)查找指定元素的位置
(9)遍历顺序表

#include <stdio.h>
#include <stdlib.h>

//int last = 5;//全局
//int a[100] = {11,22,33,44,55};//数组,用来存储有效数据

#define N 100
typedef struct 
{
	int last;//last时刻代表有效元素的个数
	int data[N];//用来存储有效数据
}seqlist_t;
//sequence 顺序
//list 表

//1.遍历顺序表,将所有的有效元素打印输出
void showSeqlist(seqlist_t* p)//实参初始化形参 seqlist_t* p = p(main函数中的p)
{
	int i;
	for(i = 0; i < p->last; i++)
	{
		printf("%d ",p->data[i]);
	}
	printf("\n");
}

//2.创建一个空的顺序表
seqlist_t* createEmptySeqlist()
{
 	seqlist_t* p = (seqlist_t*)malloc(sizeof(seqlist_t));//堆区
	if(p == NULL)
	{
		printf("malloc failed!!\n");
		return NULL;//提前结束函数
	}
	p->last = 0;//因为创建的是空的顺序表,所以last的值初始化为0,有效元素个数为0
	return p;
}
//3. 向指定的位置插入数据
int insertIntoSeqlist(seqlist_t* p, int post, int x) //seqlist_t* q = p;
{
	//0.容错判断,对插入位置是否合理,进行条件判断
	if(post < 1 || post > p->last+1 || isFullSeqlist(p))
	{
		printf("insertIntoSeqlist failed!!\n");
		return -1;//通常用-1来表达失败
	}
	
	//1.将最有一个有效元素的下标到插入位置的下标整体向后一个位置
	int i;
	for(i = p->last-1; i >= post-1; i--)
		p->data[i+1] = p->data[i];
	//2.插入数据
	p->data[post-1] = x;
	//3.有效元素个数+1
	p->last++;
	return 0;//用0来表达成功
}
//4.判断顺序表是否为满 满返回值是1,未满是0 
int isFullSeqlist(seqlist_t* p)
{
	/*
	//方法一:有效元素个数 == 数组的长度,表满
	if(p->last == N)
		return 1;
	else
		return 0;
	//方法二:
	return p->last == N ? 1 : 0;
	*/
	//方法三 
	return p->last == N;//p->last == N 表达式为真,C语言中,真用1来表达, p->last == N表达式为假,C语言中假用0来表达
}
//5. 判断是否为空 空返回值是1,未空返回值0
int isEmptySeqlist(seqlist_t* p)
{
	return p->last == 0 ? 1 : 0;
}
//6.删除指定位置的数据
int deleteFromSeqlist(seqlist_t* p, int post)
{
	int i;
	//0.容错判断 对删除位置是否合理,进行判断
	if(post < 1 || post > p->last || isEmptySeqlist(p))
	{
		printf("deleteFromSeqlist failed!!\n");
		return -1;
	}
	//1.将删除位置的后一个位置的下标到最后一个有效元素下标,整体向前移动一个位置,覆盖删除
	for(i = post; i <= p->last-1; i++)
	{
		p->data[i-1] = p->data[i];
	}
	//2.有效元素个数-1
	p->last--;
	return 0;
}
//7.求顺序表的长度,长度就是有效元素的个数
int getLengthSeqlist(seqlist_t* p)
{
	return p->last;
}
//8.清空顺序表
void clearSeqlist(seqlist_t* p)
{
	p->last = 0;
}
//9.查找指定数据出现的位置,返回数组中的位置下标
//int x,代表被查找的数据
int searchDataSeqlist(seqlist_t* p, int x)
{
	int i;
	for(i = 0; i < p->last; i++)
	{
		if(p->data[i] == x)
			return i;
	}
	return -1;//代表没有找到
}

int main(int argc, const char *argv[])
{
	seqlist_t* p = createEmptySeqlist();//得到malloc申请结构体变量空间大小的首地址
	insertIntoSeqlist(p, 1, 11);//将首地址告诉insertIntoSeqlist函数
	insertIntoSeqlist(p, 2, 22);
	insertIntoSeqlist(p, 3, 33);
	insertIntoSeqlist(p, 4, 44);
	insertIntoSeqlist(p, 5, 55);
	insertIntoSeqlist(p, 3, 1000);
	showSeqlist(p);//将首地址告诉showSeqlist函数
	deleteFromSeqlist(p,3);
	showSeqlist(p);
	printf("len is %d\n",getLengthSeqlist(p));
	printf("33的位置下标是%d\n",searchDataSeqlist(p,33));
	clearSeqlist(p);
	printf("len is %d\n",getLengthSeqlist(p));
	free(p);
	return 0;
}



//2.链表

逻辑结构:  线性结构 

存储结构:  链式存储结构

链式存储结构: 内存当中是不连续存储的,通过指针将每个节点连接在一起

//node 节点的意思
//link 链接

//定义一个节点

typedef struct node_t //注意此处的node_t不能省略不写
{
	int data;//数据域,用来保存有效数据的
	struct node_t* next;//指针域 用来指向下一个节点的指针 
}link_node_t;
 
sizeof(struct node_t) --> 8


link_node_t s;


单向链表可以分为 有头的单向链表 和 无头的单向链表 

无头单向链表:链表中的每一个节点的数据域,都是有效的数据 
有头单向链表:链表中的第一个节点的数据域是无效的,其他是有效的

###有头单向链表和无头的单向链表只是一个相对的概念

2.1 无头的单向链表
 
#include <stdio.h>

typedef struct node_t
{
	int data;//数据域
	struct node_t* next;//指针域
}link_node_t;

int main(int argc, const char *argv[])
{
	//无头单向链表,链表中的每个节点的数据域,都是有效的数据
	//1.定义5个节点
	link_node_t a = {10,NULL};
	link_node_t b = {20,NULL};
	link_node_t c = {30,NULL};
	link_node_t d = {40,NULL};
	link_node_t e = {50,NULL};
	//2.将5个节点连接在一起
	a.next = &b;
	b.next = &c;
	c.next = &d;
	d.next = &e;
	//3.定义一个头指针,保存链表第一个节点的地址
	link_node_t* p = &a;
	//4.遍历无头单向链表
	while(p != NULL)
	{
		printf("%d ",p->data);
		p = p->next;
	}
	printf("\n");
	return 0;
}

五、链式存储结构
内存中不连续存储,通过指针将每个节点链接在一起
无头链表:

有头单向链表:第一个数据域无效

尾插法:要定义一个尾指针,永远指向当前链表的尾巴,即最后一个节点

写一个有头单向链表,一直输入学生成绩,存入链表中,直到输入-1 结束程序


每输入一个学生成绩,就malloc申请一个新的节点,将输入的成绩保存到数据域,并将该新节点链接到链表的尾巴

//要求:每一个链表的节点由动态内存分配malloc得到,包括头节点

// 编程思想:

//1.malloc创建一个链表的头节点,数据域不用装东西 

//2. 
	//可以再定义一个指针变量,永远指向当前链表的尾巴
	int score; 
	while(1)
	{
		scanf("%d",score);
		if(score == -1)
			break;
		//3.申请节点大小的空间,将 score 保存到节点的 数据域score中,将这个节点连接链表的尾巴
	}
//3.循环遍历打印链表

#include <stdio.h>
#include <stdlib.h>

typedef struct node_t
{
	int data;
	struct node_t* next;
}link_node_t;

int main(int argc, const char *argv[])
{
	int score;//用来保存输入的学生成绩
	//1.创建一个头节点,作为链表的头
	link_node_t* ptail = NULL;//ptail尾指针,永远指向当前链表的尾巴
	link_node_t* phead = malloc(sizeof(link_node_t));
	if(phead == NULL)
	{
		printf("phead malloc failed!!\n");
		return -1;
	}
	phead->next = NULL;//有可能输入第一个学生成绩就是-1,循环结束了,是一个空的链表,作为遍历有头链表结束条件
	//由于最开始只有一个节点,既是头节点,也是尾节点
	ptail = phead;
	//2.循环输入学生成绩,输入一个成绩,就保存一个新创建节点的数据域中,插入在链表的尾巴上
	while(1)
	{
		printf("请输入学生成绩:\n");
		scanf("%d",&score);
		if(score == -1)
			break;
		//创建新的节点,用来保存输入的成绩
		link_node_t* pnew = malloc(sizeof(link_node_t)); //pnew永远指向新创建的节点
		if(pnew == NULL)
		{
			printf("pnew malloc failed!!\n");
			return -1;
		}
		//申请空间后,立刻赋值,将成绩存入到新创建的节点中
		pnew->data = score;//输入的成绩,保存到新节点的数据域
		pnew->next = NULL;
		//将新的节点,插入在链表的尾巴上 
		//尾插法思想:尾指针,永远指向当前链表的尾巴,也就是最后一个节点,只要让最后一个节点的next指针,指向新的节点,就算插入成功
		ptail->next = pnew;//插入在尾巴上
		//将尾指针移动当前链表的尾巴,因为插入之后,链表变长了
		ptail = pnew;//ptail = ptail->next;
	}
	//遍历有头单向链表
	while(phead->next != NULL)
	{
		phead = phead->next;
		printf("%d ",phead->data);
	}
	printf("\n");
	return 0;
}

六、顺序表总结
1.逻辑结构是线性结构,存储结构是顺序存储结构,在内存当中是连续存储的
2.顺序表优点:查找方便,因为可以通过数组下标,直接访问元素
3.顺序表缺点:a:顺序表长度固定(本质是操作的数组)
b:插入和删除麻烦

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值