将会分为三篇博客,由浅入深的介绍数据结构中的线性表,线性表是数据结构中最常用的数据结构也是最基础的数据结构,在以后学习到的栈与队列的实现、二叉树、图等都会用到线性表结构。将会分为三篇博客详细介绍线性表,本篇博客主要说一下顺序表的原理、顺序表的初始化、插入、删除、查找,并讲解一下链表的实现原理。
在正式介绍线性表之前可以先看看有关线性表的考研真题!
2010 年(顺序表)
42.(13 分)设将 n(n > 1)个整数存放到一维数组 R 中。试设计一个在时间和空间两方面都尽可能高效的算法。将 R 中保存的序列循环左移 p(0 < p < n)个位置,即将 R中的数据由(X0, X1, , Xn1)变换为(Xp, Xp+1,, Xn1, X0, X1, , Xp1)。要求:
2012 年(链表)
42.假定采用带头结点的单链表保存单词,当两个单词有相同的后缀时,则可共享相同的后缀存储空间,例如,“loading”和“being”的存储映像如下图所示。
设 str1 和 str2 分别指向两个单词所在单链表的头结点,链表结点结构为
请设计一个时间上尽可能高效的算法,找出由 str1 和 str2 所指向两个链表共同后缀的起始位置(如图中字符 i 所在结点的位置 p)。要求:
顺序表结合排序出了很多大题,链表本身出了很多大题,都非常重要!
线性表定义
线性表特点
上面两个图说的均是线性表的逻辑结构,与存储结构没有关系,具体关系如下所示。
线性表分类
#define MaxSize 50 //定义线性表的长度
typedef struct {
ElemType data[Maxsize] ; //顺序表的元素
int len; //顺序表的当前长度
} sqList; //顺序表的类型定义
ElemType指任意类型
在顺序表中增加一个元素
经过不懈的努力,终于编码完毕下面为插入元素的代码:
bool insertData(myList* mylist,int i,ElemType e){
//三个参数分别是结构体数组、元素要插入的位置、要插入的元素
//判断数组长度
if(mylist==NULL||i<=0||mylist->length+1<i||i>MaxSize){
return false;
}
int j;
for(j=mylist->length;j>=i;j--){
mylist->data[j]=mylist->data[j-1];
}
mylist->data[i-1]=e;
mylist->length+=1;
return true;
}
在顺序表中删除一个元素
删除元素有两种方式,一种是按照序号(也就是位置)删除,一种是按照元素进行删除,这里两种方法我都实现了一下;
上面循环内的公式:l.data[j-1]=l.data[j]方式往前移动数据,可以有效地防止数组越界等问题。如果不是这个公式那么需要改变循环条件。
按照序号进行删除
//删除元素(删除指定位置)
bool deleteDataByI(myList* mylist,int i){
if(mylist==NULL||i<=0||mylist->length<i||i>MaxSize){
return false;
}
int j=i;
for (;j<mylist->length;j++){
mylist->data[j-1]=mylist->data[j];
}
// 删除完毕之后,将多出来的一个空位赋上\0
mylist->data[mylist->length-1]=baseElem;
mylist->length-=1;
}
按照元素进行删除
//删除元素(遍历删除指定元素)
bool deleteDataByE(myList* mylist,ElemType e){
// 删除指定元素(搜索,删除)
if(mylist==NULL){
return false;
}
int j=0;
// 临时记下原来长度
int tempIndex=mylist->length;
// 第一遍遍历(去除相关元素)
for(;j<tempIndex;j++){
if(mylist->data[j]==e){
mylist->data[j]=baseElem;
mylist->length-=1;
}
}
// 将数组内的空缺由后面元素填补掉
int i=0;
for(;i<mylist->length;i++){
if(mylist->data[i]==baseElem){
for(j=i+1;j<tempIndex;j++){
if(mylist->data[j]!=baseElem){
mylist->data[i]=mylist->data[j];
mylist->data[j]=baseElem;
break;
}
}
}
}
}
查询元素与打印元素
//查询元素
int searchElement(myList* mylist,ElemType e){
int i=0;
for(;i<mylist->length;i++){
if(mylist->data[i]==e){
return true;
}
}
return false;
}
//打印元素
void printData(myList* mylist){
if(mylist==NULL){
printf("null");
}
int i=0;
for(;i<mylist->length;i++){
printf("%3c",mylist->data[i]);
}
printf("\n");
}
清理顺序表
memset(p->data,baseElem, MaxSize);
p->length=0;
顺序表就是我们C语言中常说的数组,无论从逻辑结构,存储结构来说都是顺序存储。有优点也有缺点,总结如下:
源码
代码思路:这里由于用的是纯c语言写的,所以自定义了bool类型,在插入数据时需要注意临界条件,不能超出数组,也不能超出现有长度+2,也就是不能随机插入在空白区域,插入之后数据之间要连贯,删除函数的话按索引删除与插入相类似,按元素删除是先删除相关元素,然后用两个索引将元素聚拢到一块,查询与打印函数比较简单就不说了!
//
// Created by Zhu Shichong on 2023/1/9.
//
#include
#include
#include
#define MaxSize 50
#define baseElem '\0'
# define bool int
# define true 1
# define false 0
typedef char ElemType;
//数组类型
typedef struct{
ElemType data[MaxSize];
int length;
}myList;
//插入元素
bool insertData(myList* mylist,int i,ElemType e){
//三个参数分别是结构体数组、元素要插入的位置、要插入的元素
//判断数组长度
if(mylist==NULL||i<=0||mylist->length+1<i||i>MaxSize){
return false;
}
int j;
for(j=mylist->length;j>=i;j--){
mylist->data[j]=mylist->data[j-1];
}
mylist->data[i-1]=e;
mylist->length+=1;
return true;
}
//删除元素(删除指定位置)
bool deleteDataByI(myList* mylist,int i){
if(mylist==NULL||i<=0||mylist->length<i||i>MaxSize){
return false;
}
int j=i;
for (;j<mylist->length;j++){
mylist->data[j-1]=mylist->data[j];
}
// 删除完毕之后,将多出来的一个空位赋上\0
mylist->data[mylist->length-1]=baseElem;
mylist->length-=1;
}
//删除元素(遍历删除指定元素)
bool deleteDataByE(myList* mylist,ElemType e){
// 删除指定元素(搜索,删除)
if(mylist==NULL){
return false;
}
int j=0;
// 临时记下原来长度
int tempIndex=mylist->length;
// 第一遍遍历(去除相关元素)
for(;j<tempIndex;j++){
if(mylist->data[j]==e){
mylist->data[j]=baseElem;
mylist->length-=1;
}
}
// 将数组内的空缺由后面元素填补掉
int i=0;
for(;i<mylist->length;i++){
if(mylist->data[i]==baseElem){
for(j=i+1;j<tempIndex;j++){
if(mylist->data[j]!=baseElem){
mylist->data[i]=mylist->data[j];
mylist->data[j]=baseElem;
break;
}
}
}
}
}
//查询元素
int searchElement(myList* mylist,ElemType e){
int i=0;
for(;i<mylist->length;i++){
if(mylist->data[i]==e){
return true;
}
}
return false;
}
//打印元素
void printData(myList* mylist){
if(mylist==NULL){
printf("null");
}
int i=0;
for(;i<mylist->length;i++){
printf("%3c",mylist->data[i]);
}
printf("\n");
}
int main() {
myList *p=(myList*)malloc(sizeof (myList));
// 初始化
memset(p->data,baseElem, MaxSize);
p->length=6;
p->data[0]='h';
p->data[1]='o';
p->data[2]='w';
p->data[3]='a';
p->data[4]='r';
p->data[5]='e';
printf("before insert : ");
printData(p);
insertData(p,3,'v');
insertData(p,6,'v');
insertData(p,8,'v');
printf("after insert : ");
printData(p);
printf("delete by index : ");
deleteDataByI(p,4);
printData(p);
printf("delete by element : ");
deleteDataByE(p,'v');
printData(p);
printf("search: %d\n", searchElement(p,'a'));
printf("search: %d", searchElement(p,'c'));
return 0;
}
在下一小节我们将会介绍C语言链表的增删改查与销毁,如有兴趣请多多关注!