您的位置:首页 > 理论基础 > 数据结构算法

数据结构实战——线性结构之静态数组表示法

2014-10-21 19:41 555 查看

转载请声明出处:/article/7920488.html

说在前面

这学期在上《数据结构及应用算法》这门课,收获很多。所以打算在这里以博客的形式记录下自己的学习过程,和大家分享,共同进步。本实战系列需要注意的问题是,由于引用数据类型&在C语言中不支持,但是它的概念非常容易被大家接受,所以我采用了C语言代码和C++编译环境进行混合,如果没有学过C++的,完全可以用指针修改一下参数就ok了,后面就不在赘述。

线性表的概念

线性表是n(n≥0)个数据元素的有限序列,这些数据元素同属于一个集合,在这个序列中相邻的数据元素之间存在一种相对的位置关系,通常记作:L=(a1,a2,...an)。在序列中,第i-1元素位于第i元素的前面,称为直接前驱元素,第i+1元素位于第i元素后面,称为直接后继元素。i正是标识数据元素相对位置的编号,称为位序。元素的个数称为长度。

线性表的存储结构一般考虑两种方式:顺序存储链式存储。顺序存储就是在存储器的一块连续的区域中把元素按照存储器单元的自然次序一一存放,借助于存储器的连续性来体现元素之间的逻辑关系,逻辑位置与物理位置一致。链式存储则是利用指针链接来反映元素之间的逻辑关系,逻辑位置与物理位置未必一致。

当用顺序的方式实现线性表的存储时,无外乎两种,静态数组表示法和动态数组表示法。这里先介绍静态表示法,后面一篇博客介绍动态表示法。

线性表静态数组表示法的定义

这里只需注意一点,位序 i 和数组下标 j 的关系是:i = j + 1

/* 线性表的静态数组表示法 -- 定义 */

#ifndef SLISTOPERATION_H_INCLUDED
#define SLISTOPERATION_H_INCLUDED

#define MAX_NUM 200
typedef struct{
int A[MAX_NUM];//定义一个MAX_NUM长度的静态数组,元素数据类型为Elemtype,可以是int,char,结构体等。
int listsize;//线性表的容量。
int listlength;//当前线性表的长度。
}SLIST;//关于typedef用法:http://www.cnblogs.com/qyaizs/articles/2039101.html

</a>void InitList(SLIST &L);
void DestroyList(SLIST &L);
void ClearList(SLIST &L);
bool ListEmpty(SLIST L);
int ListLength(SLIST L);
int GetElem(SLIST L, int i, int &e);
int LocateElem(SLIST L, int e);
bool PriorElem(SLIST L, int cur_e, int &pre_e);
bool NextElem(SLIST L, int cur_e, int &next_e);
int ListInsert(SLIST &L, int i, int e);
int ListDelete(SLIST &L, int i, int &e);
void ListTravers(SLIST L);
void merge(SLIST &L1, SLIST &L2);
void minus(SLIST &L1, SLIST &L2);

#endif // SLISTOPERATION_H_INCLUDED


线性表静态数组表示法的12种基本操作

这部分主要用C语言实现了顺序表的12种基本操作,以及两个集合的基本并、减操作,用以示例如何运用基本操作函数:

/* 线性表的静态数组表示法 -- 12种基本操作 */

/*位序i = [1 ~ listlength],数组下标i-1 = [0 ~ listlength-1]*/

#include<stdio.h>
#include "SlistOperation.h"

/**12个基本操作*/

void InitList(SLIST &L){    //创建一个空线性表
L.listsize = MAX_NUM;
L.listlength = 0;
}

void DestroyList(SLIST &L){ //销毁线性表
L.listsize = 0;
L.listlength = 0;
}

void ClearList(SLIST &L){   //线性表重置空
L.listlength = 0;
}

bool ListEmpty(SLIST L){    //判断线性表是否为空
if (L.listlength == 0)
return true;
else
return false;
//return !(L.listlength);
//return (L.listlength == 0);
}

int ListLength(SLIST L){    //返回线性表长度
return L.listlength;
}

int GetElem(SLIST L, int i, int &e){    //获取线性表位序为i的元素
//合法性校验
if (i < 1)  return -1;
if (i > L.listlength)   return -2;
e = L.A[i-1];   return 0;
}

int LocateElem(SLIST L, int e){    //返回线性表首个e元素的位序
for (int i = 0; i < L.listlength; i++){
if (L.A[i] == e)
return i+1;
}
return 0;
}

bool PriorElem(SLIST L, int cur_e, int &pre_e){ //获取cur_e元素的直接前驱
if (cur_e == L.A[0])    return false;
for (int i = 1; i < L.listlength; i++){
if (cur_e == L.A[i]){
pre_e = L.A[i-1];
return true;
}
}
return false;
}

bool NextElem(SLIST L, int cur_e, int &next_e){ //获取cur_e元素的直接后继
if (cur_e ==    L.A[L.listlength-1])   return false;
for (int i=0; i < L.listlength-1; i++){
if(cur_e == L.A[i]){
next_e = L.A[i+1];
return true;
}
}
return false;
}

int ListInsert(SLIST &L, int i, int e){ //在顺序表位序为i的元素前面插入元素e
//合法性校验
if (i < 1)    return -1;
if (i > L.listlength+1)   return -2;
if (L.listlength == L.listsize) return -3;  //静态数组表示线性表的情况,表满了,就不插入了。
for (int j = L.listlength; j >= i; j--){
L.A[j] = L.A[j-1];
}
L.A[i-1] = e;
L.listlength++;
return 0;
}

int ListDelete(SLIST &L, int i, int &e){    //删除顺序表位序为i的元素
//合法性校验
if (i < 1)  return -1;
if (i > L.listlength)   return -2;
e = L.A[i-1];
for (int j = i; j < L.listlength; j++){
L.A[j-1] = L.A[j];
}
L.listlength--;
return 0;
}

/*顺序表的插入、删除动作,都需要O(n)的时间复杂度,这个时间消耗在长度较大时是不容忽视的。
缺陷产生的原因是因为顺序表是依靠内存的连续性来反映元素之间的逻辑关系而造成的。
*/

void ListTravers(SLIST L){  //依次输出顺序表的所有元素(这里可以对顺序表进行一些操作,比如求和、最大值、输出素数等)
for (int i = 0; i < L.listlength; i++){
printf("%d ",L.A[i]);
}
printf("\n");
}

void merge(SLIST &L1, SLIST &L2){
int temp;
while (!ListEmpty(L2)){
ListDelete(L2,1,temp);
if (!LocateElem(L1,temp)){
ListInsert(L1,L1.listlength+1,temp);
}
}
DestroyList(L2);
}

void minus(SLIST &L1, SLIST &L2){
int temp,pos;
while (!ListEmpty(L2)){
ListDelete(L2,1,temp);
if ((pos = LocateElem(L1,temp)) != 0){
ListDelete(L1,pos,temp);
}
}
DestroyList(L2);
}


线性表静态数组表示法的应用

完整的调用操作函数示例:

/* 线性表的静态数组表示法 -- 应用 */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "SlistOperation.h"

int main(){
int temp,select,item,i=0;
char str[20],*th,ch;
SLIST La,Lb;
InitList(La);
InitList(Lb);
printf("请给 La 顺序表赋值 <interger> :\n");
gets(str);
th = strtok(str," ");
while(th != NULL){
temp = atoi(th);
ListInsert(La,La.listlength+1,temp);
th = strtok(NULL," ");
}

printf("\n");
printf("1: 创建一个空线性表 \n");
printf("2: 销毁线性表 \n");
printf("3: 线性表重置空 \n");
printf("4: 判断线性表是否为空 \n");
printf("5: 返回线性表长度 \n");
printf("6: 获取线性表位序为i的元素 \n");
printf("7: 返回线性表首个e元素的位序 \n");
printf("8: 获取cur_e元素的直接前驱 \n");
printf("9: 获取cur_e元素的直接后继 \n");
printf("10: 在顺序表位序为i的元素前面插入元素e \n");
printf("11: 删除顺序表位序为i的元素 \n");
printf("12: 依次输出顺序表的所有元素 \n");
printf("13: A并B \n");
printf("14: A - B \n");

printf("请选择 (1---14)  \n\n");
scanf("%d",&select);
switch(select){
case 1:
SLIST Lt;
InitList(Lt);
printf("已创建顺序表Lt!\n");
break;
case 2:
printf("确定要删除顺序表La? <y/n>\n");
ch = getchar();
if (ch == 'y' || ch == 'Y'){
DestroyList(La);
printf("已销毁顺序表La!\n");
}
else
printf("非法输入!\n");
break;
case 3:
ClearList(La);
printf("顺序表La已置空!\n");
break;
case 4:
if (ListEmpty(La))
printf("顺序表La是空的!\n");
printf("顺序表La非空!\n");
break;
case 5:
printf("顺序表La的长度是 %d\n",ListLength(La));
break;
case 6:
printf("请输入你想获取第几位数据?\n");
scanf("%d",&temp);
if (!(GetElem(La,temp,item)))
printf("第%d位元素是:%d\n",temp,item);
else
printf("非法位序!\n");
break;
case 7:
printf("请输入你想要查找的元素: ");
scanf("%d",&temp);
if ((item = LocateElem(La,temp)) == 0)
printf("你所查找的元素不存在!\n");
else
printf("%d元素首次出现在第%d位上!\n",temp,item);
break;
case 8:
printf("你想获得哪个元素值的前驱?\n");
scanf("%d",&temp);
if(PriorElem(La,temp,item))
printf("首次出现的%d元素的直接前驱是 %d\n",temp,item);
else
printf("输入非法!\n");
break;
case 9:
printf("你想获得哪个元素的后继?\n");
scanf("%d",&temp);
if(NextElem(La,temp,item))
printf("首次出现的%d元素的直接后继是 %d\n",temp,item);
else
printf("输入非法!\n");
break;
case 10:
printf("您想在第几个元素前面插入新元素?<1-%d>\n",ListLength(La)+1);
scanf("%d",&temp);
printf("您想插入的新元素是:");
scanf("%d",&item);
if(!ListInsert(La,temp,item)){
printf("插入成功!\n");
printf("新顺序表为:");
ListTravers(La);
}
else
printf("输入错误!\n");
break;
case 11:
printf("请输入您想删除的位序:");
scanf("%d",&temp);
if(!ListDelete(La,temp,item))
printf("元素%d删除成功!\n",item);
else
printf("非法输入!\n");
break;
case 12:
printf("你输入的顺序表为:");
ListTravers(La);
break;
case 13:
getchar();
printf("请给 Lb 顺序表赋值 <interger> :\n");
gets(str);
th = strtok(str," ");
while(th != NULL){
temp = atoi(th);
ListInsert(Lb,Lb.listlength+1,temp);
th = strtok(NULL," ");
}
merge(La,Lb);
printf("合并后的 La 为:");
ListTravers(La);
break;
case 14:
getchar();
printf("请给 Lb 顺序表赋值 <interger> :\n");
gets(str);
th = strtok(str," ");
while(th != NULL){
temp = atoi(th);
ListInsert(Lb,Lb.listlength+1,temp);
th = strtok(NULL," ");
}
minus(La,Lb);
printf("合并后的 La 为:");
ListTravers(La);
break;
}
return 0;
}


程序运行结果示例,截图如下:




好了,这部分的内容就到这儿啦。有问题请联系我:lichunchun4.0@gmail.com

转载请声明出处:http://blog.csdn.net/zhongkelee

源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: