学习完数据结构到现在已经好几年,也忘了差不多了,最近重新复习起来,发现自己很多东西都忘掉了。所以现在整理这个学习笔记,加上自己的一些理解,由浅入深,也希望能给有需要的初学者们了解一下。
最简单的数据结构
在学习了数据类型,我们知道了“int i”表示“i”这个变量意思是“i”为整型的一种数据类型。进而学习了数组,我们知道了“int a[3]”表示这是都是存放整型的,长度为3的一种数据类型。
#include<stdio.h>
int main(){
int a[3]={1,2,3};
for(int i=0;i<3;i++){
printf("第%d个数据为:%d\n",i+1,a[i]);
}
return 0;
}
运行效果:
我以下图为例,浅红色格子代表内存中存储的数据:
由此,我们可以由以上的数组建立一个简单的数据结构SeqList:
#include<stdio.h>
// 固定写法,定义一个名为SeqList的结构体
typedef struct SeqList {
int data[3];
int length;
}Array; // 给结构体命名为Array
int main(){
// 定义array变量
Array array;
// 分别给结构体中的数据赋值
array.data[0]=1;
array.data[1]=2;
array.data[2]=3;
array.length=3;
printf("结构体的长度为:%d\n",array.length);
for(int i=0;i<array.length;i++){
printf("第%d个数据为:%d\n",i+1,array.data[i]);
}
return 0;
}
运行效果:
我们会发现,上面的结构体输出的内容和原本使用数组的效果相差无几,区别在于仅多了一个“length”(长度)。但多了这个长度,我们就可以在遍历时,不必写死循环的次数,增加了灵活性了。
顺序表的方法
我们在上面的例子中对结构体数据赋值的方式,比用数组麻烦多了,所以接下来我们要定义一些方法,才能体现得出数据结构的魅力。
初始化、插入、遍历的方法
#include<stdio.h>
//固定写法,定义一个名为SeqList的结构体
typedef struct SeqList {
//定义一个长度为5的数据空间
int data[5];
int length;
}Array; //给结构体命名为Array
//初始化顺序表
void SeqListInit(Array* array){
array->length=0;
}
//顺序表插入的方法(末尾插入)
void SeqListInsert(Array* array,int data){
array->data[array->length] = data;
array->length++;
}
//打印顺序表
void SeqListPrintf(Array array){
printf("结构体的长度为:%d\n",array.length);
for(int i=0;i<array.length;i++){
printf("第%d个数据为:%d\n",i+1,array.data[i]);
}
}
int main(){
//定义array变量
Array array;
//初始化顺序表(采用指针传递结构体)
SeqListInit(&array);
//分别给结构体中的数据赋值
SeqListInsert(&array,1);
SeqListInsert(&array,2);
SeqListInsert(&array,3);
//打印顺序表
SeqListPrintf(array);
return 0;
}
运行效果还是一样的,就不额外截图了。
我们对比数组的赋值、遍历可以发现,在我们的这个结构体的赋值中,通过调用插入方法,我们已经不再需要将数据指定插入到数组的第几个位置,大大地提升了我们对于数据插入的灵活性。同时,我们初始创建结构体时,已经一次性开辟好了一个空间为5的数组空间,而不需要逐个赋值时逐个开辟空间,提升了程序效率。
规范顺序表结构及方法
在以上的代码中,我们的顺序表已经有了雏形,但其中还是有很多风险的,例如我们只开辟了一个长度为5的数组空间,如果插入的数据多了,是不是又要去修改代码呢?如果我们一下子开辟的空间多了,很明显又过于浪费,因此我们需要做到动态开辟空间。同时,在插入时,假如插入的数据量超过了我们开辟的内存空间,程序也必定出错。
因此,我对顺序表的其他方法进行了补充:
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 100
#define DefaultSize 10
#define TRUE 1
#define FALSE 0
#define ERROR 0
typedef int DataType;
//固定写法,定义一个名为SeqList的结构体
typedef struct SeqList {
DataType* data;
int length;
int maxLength;
}SeqList;
//动态开辟内存空间
int SeqListAddSize(SeqList* seqList){
if(seqList->length+DefaultSize > MaxSize){
printf("已超出最大分配空间\n");
return ERROR;
}
seqList->data = (DataType*)realloc(seqList->data,(seqList->length+DefaultSize)*sizeof(DataType));
seqList->maxLength+=DefaultSize;
return TRUE;
}
//初始化顺序表
void SeqListInit(SeqList* seqList){
seqList->data = (DataType*)malloc(DefaultSize*sizeof(DataType));
seqList->length=0;
seqList->maxLength=DefaultSize;
}
//判断顺序表是否为空
int SeqListWhetherEmpty(SeqList seqList){
return seqList.length == 0 ? TRUE : FALSE;
}
// 指定位置插入
int SeqListInsertByIndex(SeqList* seqList,DataType data,int index){
if(index<1 || index>seqList->length+1){
printf("插入位置不正确\n");
return ERROR;
}
// 检查空间大小
if(seqList->length >= seqList->maxLength){
if(!SeqListAddSize(seqList)){
printf("插入数据失败!\n");
return ERROR;
}
}
// 插入到中间位置时,将后几项都向后移动一位,最后将数据插入到指定的位置
for(int i=0;i<seqList->length-index+1;i++){
seqList->data[seqList->length-i]=seqList->data[seqList->length-i-1];
}
seqList->data[index-1]=data;
seqList->length++;
return TRUE;
}
//头插入
void SeqListFirstInsert(SeqList* seqList,DataType data){
SeqListInsertByIndex(seqList,data,1);
}
//末尾插入
void SeqListInsert(SeqList* seqList,DataType data){
SeqListInsertByIndex(seqList,data,seqList->length+1);
}
// 删除指定位置元素
int SeqListRemoveByIndex(SeqList* seqList,int index){
if(index<1 || index>seqList->length){
printf("删除位置不正确\n");
return ERROR;
}
// 删除时,将后几项都向前移动一位
for(int i=index-1;i<seqList->length-1;i++){
seqList->data[i]=seqList->data[i+1];
}
seqList->length--;
return TRUE;
}
// 删除第一个元素
void SeqListRemoveFirst(SeqList* seqList){
SeqListRemoveByIndex(seqList,1);
}
// 删除最后一个元素
void SeqListRemoveLast(SeqList* seqList){
SeqListRemoveByIndex(seqList,seqList->length);
}
// 获取指定位置元素
DataType SeqListGetElementByIndex(SeqList* seqList,int index){
if(SeqListWhetherEmpty(*seqList)){
printf("顺序表为空");
return NULL;
}
if(index<1 || index>seqList->length){
printf("查找位置不正确\n");
return NULL;
}
return seqList->data[index-1];
}
// 获取第一个元素
DataType SeqListGetFirstElement(SeqList* seqList){
return SeqListGetElementByIndex(seqList,1);
}
// 获取最后一个元素
DataType SeqListGetLastElement(SeqList* seqList){
return SeqListGetElementByIndex(seqList,seqList->length);
}
// 销毁顺序表
void SeqListDestroy(SeqList* seqList){
free(seqList->data);
seqList->data=NULL;
seqList->length=0;
seqList->maxLength=0;
printf("顺序表已销毁");
}
//打印顺序表
void SeqListPrintf(SeqList seqList){
printf("遍历顺序表-----长度为:%d\n",seqList.length);
for(int i=0;i<seqList.length;i++){
printf("第%d个数据为:%d\n",i+1,seqList.data[i]);
}
}
int main(){
//定义array变量
SeqList array;
//初始化顺序表(采用指针传递结构体)
SeqListInit(&array);
//分别给结构体中的数据赋值
SeqListInsert(&array,1);
SeqListFirstInsert(&array,2);
SeqListInsert(&array,3);
SeqListInsertByIndex(&array,4,2);
SeqListInsertByIndex(&array,5,3);
SeqListInsertByIndex(&array,6,1);
//打印顺序表
SeqListPrintf(array);
printf("第一个元素是%d\n",SeqListGetFirstElement(&array));
printf("最后一个元素是%d\n",SeqListGetLastElement(&array));
SeqListRemoveByIndex(&array,4);
SeqListRemoveFirst(&array);
SeqListRemoveLast(&array);
//打印顺序表
SeqListPrintf(array);
SeqListDestroy(&array);
return 0;
}
运行效果如图:
此处卖个关子,按照代码来执行,最终的数据排序是怎么样的呢?欢迎在评论区留言!
学习参考链接: