目录
一.概述
1.什么是数据结构
数据结构=结构定义+结构操作
结构定义:在结构体中比如int age; double height;
结构操作:这个数据结构支持哪些操作,比如树型结构会支持插入删除旋转等操作。
数据结构就是去定义一个性质并且去维护这个性质。
2. 学习路线
3.结构体知识补充
最基本的struct用法
#include<stdio.h> #include<string.h> struct book{ char title[100]; char author[100]; }boo; //这个自定义的类型的类型名就是 struct book int main(){ struct book books[10];//自定义类型的数组 strcpy(books[0].title,"成龙历险记"); strcpy(books[0].author,"成龙"); printf("%s %s",books[0].title,books[0].author); return 0; }
1.struct book 代表我们自定义的类型名,用这个类型定义变量
加上typedef的struct用法
#include<stdio.h> #include<string.h> typedef struct book{ char title[100]; char author[100]; }book; //这个自定义的类型的类型名就是 struct book int main(){ book books[10];//自定义类型的数组 strcpy(books[0].title,"成龙历险记"); strcpy(books[0].author,"成龙"); printf("%s %s",books[0].title,books[0].author); return 0; }
1.typedef 名字1 名字2 意思是将名字2来代替名字1
在这里就让book 代替了 struct book
也可以下面这样重命名
#include<stdio.h> #include<string.h> struct book{ char title[100]; char author[100]; }; typedef struct book book; //这个自定义的类型的类型名就是 struct book int main(){ book books[10];//自定义类型的数组 strcpy(books[0].title,"成龙历险记"); strcpy(books[0].author,"成龙"); printf("%s %s",books[0].title,books[0].author); return 0; }
定义结构体的时候同时定义一个该结构体的变量
#include<stdio.h> #include<string.h> struct book{ char title[100]; char author[100]; } books[10]; typedef struct book book; //这个自定义的类型的类型名就是 struct book int main(){ strcpy(books[0].title,"成龙历险记"); strcpy(books[0].author,"成龙"); printf("%s %s",books[0].title,books[0].author); return 0; }
二.顺序表
将数组封装成为顺序表数据结构,为什么将数组封装成顺序表这种数据结构?
为了让数组功能更加强大,顺序表其实是表现的像数组,但比数组功能强大。
结构功能
有下标的存储数据的容器
结构定义
size:记录总共可以存储多少元素
length:记录已经存储了多少元素
*data:存放元素
结构操作
1.初始化顺序表
2.销毁顺序表
3.插入数据
4.删除数据
5.输出数据
6.扩容
#include<stdio.h> #include<stdlib.h> #include<time.h> //顺序表的结构定义 typedef struct Vector{ int *data; int size,length; } Vector; //初始化一个含有n个元素的顺序表 Vector *init(int n){ //Vector *类型说明,用该类型能定义一个指向Vector类型的指针 //指针就像是钥匙,想要进入房间,首先要先有钥匙 //定义了vec这把钥匙,为vec订制个房间,也就是分配地址 //房间的大小是一个Vector的大小 //用钥匙去取房间的东西,vec->data取到data,vec->size,取到size Vector *vec = (Vector *)malloc(sizeof(Vector)); vec->data = (int *)malloc(sizeof(int) * n); vec->size = n; vec->length = 0; return vec; } int expand(Vector *vec){ //重新分配空间,将顺序表扩大两倍 //realloc这个方法若重新分配成功了,会销毁之前的空间,返回重新申请的空间的首地址 /* realloc分配空间的原理: 首先尝试在原有地址后面增加地址,如果增加地址成功,则返回这一片地址的首地址,会和之前的首地址值相同 如果不能,则分配新的空间,并且将原先地址中的数据拷贝进来,将原先空间释放,返回新的首地址值 如果申请新空间失效,则不会释放原来的空间,会返回一个空地址。 */ int new_size = vec->size * 2; //下面这种写法会导致内存泄漏,如果申请空间失败,返回了空地址,原先的地址就找不到了,失去了这个地址的索引信息 //vec->data = (int *)realloc(vec->data,sizeof(int)*vec->size); int *p = (int *)realloc(vec->data,sizeof(int)*new_size); if(p==NULL) return 0; vec->size = new_size; vec->data = p; printf("expand vector size to %d success\n",vec->size); return 1; } //在顺序表中vec中的index位置插入val值,返回int类型,1代表插入成功,2代表插入失败 int insert(Vector *vec,int index,int val){ //先判断插入值的合法性 if(vec == NULL) return 0; //顺序表还没有定义 if(vec->length == vec->size) { //这个时候顺序表满了,定义数组时,长度是固定的,满了就不能该了 //而顺序表功能是比数组强大的,在这里添加扩容操作 if(!expand(vec)) return 0; } if(index < 0||index > vec->length) return 0; //插入的位置错误 //插入元素 //当前length的值正好是最后一个待添加元素的下标 //假如要在下标2插入,则包括下标2之后的元素都要往后移动 //i=vec->length 第一个要被移动的元素的目的地 //i>index 表示被移动的元素都被移动到index之后 for(int i = vec->length; i>index; i--){ vec->data[i] = vec->data[i - 1]; } vec->data[index] = val; vec->length++; return 1; } int erase(Vector *vec,int index){ //判断不能删除的情况 if(vec == NULL) return 0; if(vec->length == 0) return 0; if(vec->length <= index || index < 0) return 0; //index之后的元素都向前移动一格 for(int i = index + 1; i < vec->length; i++){ vec->data[i - 1] = vec->data[i]; } vec->length--; return 1; } //输出顺序表 void outPut(Vector *vec){ printf("Vector(%d) = [",vec->length); for(int i = 0;