数据结构之线性表
1:线性表:谈到线性表,可以联想到26个英语字母,他们从逻辑上组成一个有序的序列就是线性表,另外,线性表也可以是班上的成绩登记表,其中包括学号,姓名,还有各科的成绩等等。对于一个非空的线性表,注意:各个元素的长度是相同的:
2:线性表的基本运算包括 a:初始化 b计算表长 c获取结点 d查找结点e插入结点 f删除结点
在这里,我们讨论了线性表的逻辑结构和数据运算,还没有对其存储结构进行讨论,在计算机中,线性表采用二种方法来存储,一种是顺序存储,另一种是链式存储,顺序存储的线性表叫顺序表,链式存储的表叫链表
A:顺序结构表
因为顺序结构表在存储方式上是连续的,因此,只要知道该顺序表的首地址,以及每个元素占用的存储长度,就可以计算出任何一个数据元素的位置(也就是可以计算出任何衣蛾结点的位置),这种思想是我们操作顺序表结构的基本思想Loc(Ai) = Loc(a1)+(i-1)*c;
操作顺序表的步骤
1:准备数据:也就是准备顺序表中需要用到的变量以及数据结构等等
示例代码:
#define MAXLEN 100 //定义顺序表的最大长度 typedef struct { char key[10];//定义节点关键字 char name[20]; int age; }DATA;//定义结点类型 typedef struct { DATA ListData[MAXLEN+1];//保存顺序表的结构数组 int ListLen;//顺序表已保存的节点数 }SLType;
其实这里我们定义了一个顺序表,这里可以记录100个学生的基本情况,其中顺序表的数据元素类型是DATA,以及顺序表的数据结构SLType。在数据结构SLType中,ListLen为顺序表已存在的结点数量,也就是当前顺序表的长度,ListData是一个数组,用来存放各结点数据
2:初始化一个顺序表
在使用顺序表之前,我们要创建一个空的顺序表,也就是初始化顺序表,这里程序中只需要设置顺序表的结点数量ListLen等于0即可。在后面添加的元素将从顺序表的第一个位置存储
void SLInit(SLType *SL) { SL->ListLen =0;//初始化顺序表 }
需要注意的是,我们这里没有清空顺序表,如果原来顺序表中有数据,也会被覆盖,但是不会影响chaozuo
3:计算顺序表的长度
示例代码:
int SLLength(SLType *SL) { return(SL->ListLen);//返回顺序表的结构 }
计算顺序表的结构也就是
插入结点:在线性表L中插入一个新的结点,使得结点后面的编号依次加一,这是,插入新的结点后,线性表的长度将变为N+1,插入结点的难点在于随后的每个数据都要进行移动计算量比较大
int SLInsert(SLType*SL,int n,DATA data) { int i; if(SL ->ListLen >= MAXLEN)//顺序表的结点数量已经超过最大数量 { printf("顺序表已满,不能插入结点"); return 0; } if(n<1 ||n>SL->ListLen-1)//插入的结点不正确 { printf("插入元素序号错误,不能插入元素"); return 0; } for(i = SL->ListLen;i>=n;i--)//将表中的数据向后移动一位 { SL->ListData[i+1] = SL->ListData[i]; } SL->ListData[n] = data;//插入结点 SL ->ListLen++;//顺序表的结点数量增加1 return 1;//插入成功表示返回1 }
这里程序要先判断顺序表的结点数量是否超过最大的数量,以及插入结点的序号是否正确,但条件满足的时候,便将顺序表中的数据向后移动,同时插入结点,并更新ListLen
追加结点:
int SLAdd(SLType*SL,DATA data) { if(SL->Listen>=MAXLEN) { printf("顺序表已满,不能在添加结点"); return 0; } SL->ListData[++SL->ListLen] = data; return 1; }
追加结点并不是基本的数据结构操作,但是由于算法比较简单,这里单独给出代码
删除结点:
int SLDelete(SLType*SL,int n) { int i; if(n<1||n>SL->ListLen+1) { printf("删除结点序号错误,不能删除结点"); return 0; } for(i = n;i<ListLen;i++)//将顺序表中的数据向前移动即可 { SL->ListData[i] = SL->ListData[i+1]; } SL->ListLen --; return 1;//成功的话,返回值为1 }
这里首先判断待删除的及结点序号是否正确,如果正确,开始移动数据,并更新结点数量ListLen
查找结点
查找结点,顾名思义就是查找值为x的结点,并返回该结点在线性表中的位置,如果在线性表中没有找到结点为x的结点则返回一个错误标志,根据x类型的不同,查找的方式可以分为按序号查找结点或按关键字查找结点
按照序号查找结点:
DATA*SLFindByNum(SLType*SL,int n) { if(n<1||n>SL->ListLen+1) { printf("结点序号错误"); return NULL; } return &(SL->ListData[n]); }
对于一个顺序表,序号就是数据元素在数组中的位置,也就是数组元素的下标标号,按照序号查找结点是顺序表查找的最常用的方法,这是因为顺序表存储本身就是一个数组
按照关键字查找结点:
int SLFindByCont(SLType*sl,char *key) { int i; for(i= 1;i<SL->ListLen;i++) { if(strcmp(sl->Data[i].key,key)==0) return i; } return 0; }
这是一个比较常见的按照关键字进行查找的例子,我们可以看作是学生的学号为关键字
显示所有结点:
int SLAll(STLType*SL) { int i; for(i=1;i<SL->ListLen;i++) { printf("(%s,%S,%D)\N",Sl->ListData[i].key,SL->ListData[i].name,SL->ListData[i].age); return 0; } }
显示所有结点的数据并不是数据结构的基本运算,因为他可以是简单的逐个引用结点来实现,这里单独列出一个函数,用来操作显示所有结点
冒泡法排序:
//冒泡法排序 从小到大依次排序 #include<stdio.h> #define Len 10 //冒泡法的基本算法 void BubbleSort(int *a) { int i,j,temp; for(i = 0;i<Len-1;i++) for(j = Len-1;j>i;j--)//从后面开始往前面比较这样比较容易理解 { if(a[j-1]>a[j]) { temp = a[j-1]; a[j-1] = a[j]; a[j] = temp; } } } int main() { int a[Len],i; printf("please input a[10]\n"); for(i = 0;i<Len;i++) scanf("%d",&a[i]); BubbleSort(a); printf("the order is:\n"); for(i = 0;i< Len;i++) printf("%3d",a[i]); printf("\n"); return 0; }
顺序表操作
#include<stdio.h> #include<string.h> #define MAXLEN 100 typedef struct { char key[10]; char name[20]; int age; }DATA; typedef struct { DATA ListData[MAXLEN]; int ListLen; }SLType; //初始化顺序表 void SLInit(SLType *SL) { SL->ListLen = 0; } //计算顺序表的长度 int SLLength(SLType *SL) { return (SL->ListLen); } //插入结点 int SLInsert(SLType*SL,int n,DATA data) { int i; if(SL->ListLen >=MAXLEN) { printf("结点已经满了"); return 0; } if(n<0||n>MAXLEN) { printf("插入的结点有误"); return 0; } for(i = SL->ListLen;i>n;i--) { SL->ListData[i+1] = SL->ListData[i]; } SL->ListData[n] = data; SL->ListLen ++; return 1; } //增加结点 int SLAdd(SLType *SL,DATA data) { if(SL->ListLen >MAXLEN) { printf("增加失败,结点已经满了"); return 0; } SL->ListLen ++; SL->ListData[SL->ListLen] = data; return 1; } //删除结点 int SLDelete(SLType*SL,int n) { int i; if(n<0||n>SL->ListLen+1) { printf("删除结点失败"); return 0; } for(i = n;i<SL->ListLen;i++) { SL->ListData[i] = SL->ListData[i+1]; } SL->ListLen--; return 1 ;} //按序号查找 DATA *SLFindByNum(SLType*SL,int n) { if(n<0||n>SL->ListLen) { printf("查找结点失败"); return NULL; } return &(SL->ListData[n]);} //按关键字查找 int SLFindByCont(SLType*SL,char *key) { int i; for(i=0;i<SL->ListLen;i++) { if(strcmp(SL->ListData[i].key,key)==0) return i; } return 0; } //显示所有结点 int SLAll(SLType*SL) { int i; for(i = 0;i<SL->ListLen;i++) { printf("%s,%s,%d",SL->ListData[i].key,SL->ListData[i].name,SL->ListData[i].age); } return 0; } int main() { int i; SLType SL; DATA data; DATA *pdata; char key[10]; printf("顺序表演示\n"); SLInit(&SL);//初始化顺序表 printf("顺序表初始化完成\n"); do { printf("输入添加的结点(学号,姓名,年龄)"); fflush(stdin);//清空输入缓存区 scanf("%s%s%d",&data.key,&data.name,&data.age); if(data.age) { if(!SLAdd(&SL,data))//添加结点失败 { break; } } else//年龄为0,退出死循环 { break; } }while(1); printf("\n顺序表中的结点顺序\n"); SLAll(&SL);//显示所有结点数据 fflush(stdin); printf("\n需要取出的结点\n"); scanf("%d",&i); pdata = SLFindByNum(&SL,i); if(pdata) { printf("第%d个结点为:(%s,%s,%d)",i,pdata->key,pdata->name,pdata->age); } fflush(stdin); printf("\n要查找的结点的关键字\n"); scanf("%s",key); i = SLFindByCont(&SL,key); pdata = SLFindByNum(&SL,i); if(pdata) { printf("第%d个结点为:(%s,%s,%d)\n",i,pdata->key,pdata->name,pdata->age); // getch(); return 0; } return 0; }
版权所有,转载请注明链接地址: