小猪的数据结构学习笔记(二)
线性表中的顺序表
本节引言:
在上个章节中,我们对数据结构与算法的相关概念进行了了解,知道数据结构的
逻辑结构与物理结构的区别,算法的特性以及设计要求;还学了如何去衡量一个算法
的好坏,以及时间复杂度的计算!在本节中我们将接触第一个数据结构——线性表;
而线性表有两种表现形式,分别是顺序表和链表;学好这一章很重要,是学习后面的基石;
这一节我们会重点学习下顺序表,在这里给大家一个忠告,学编程切忌眼高手低,看懂不代表自己
写得出来,给出的实现代码,自己要理解思路,自己写出来!写多了就有感觉了!多思考!!
另外附上学习数据结构的一个利器,数据结构演示动画,在本文结尾给出!
好了,废话就这么多!
路线图解析:
①抽象数据类型就那三要素:数据,数据之间的关系,和数据的操作
②线性表就是按一条线排列的数据集合,1对1,除了首元和尾元,其他元素都有直接前驱和直接后继
③顺序表有点像以前学习的数组,要小心注意表中的第i个元素是对应 i - 1那个位置的数据的!!!!
④基本存储结构要牢记,至于12个基本操作,除了插入和删除有点小难度,其他的都很简单,要自己将代码写多几遍哦!
⑤求并集的那个,也不是很难懂,自己拿笔画下图,想一想应该就懂了!去除表中的重复元素占时没想到什么好的方法,有好的欢迎提出!
正文:
<span style="font-family:Microsoft YaHei;">#define MAXSIZE 20
#define INCREMENT 10
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
//定义一个int数据类型的别名
//这里因为演示采用int,实际使用的通常是复合的数据类型
typedef int ElemType;
typedef int Status;
typedef struct
{
ElemType *elem; //存储空间的起始地址
int length; //表的当前长度
int listsize; //表的总共存储容量(sizeof(ElemType))
}SqList;</span>
<span style="font-family:Microsoft YaHei;">//创建一个空表:
void InitList(Sqlist &L)
{
L.elem = (ElemType *)malloc(MAXSIZE * sizeof(ElemType));
if(!L.elem) exit(ERROR);
L.length = 0;
L.listsize = MAXSIZE;
} </span>:步骤:
①申请表的存储空间,将空间的其实地址赋值给elem,然后通过判断elem是否为空,从而知道内存是否分配成功
②将表的当前长度length设置为0,将表的大小listsize设置为MAXSIZE
<span style="font-family:Microsoft YaHei;">//将表置为空表
void ClearList(SqList &L)
{
L.length = 0;
} </span>只需要将表的长度length设置为0就可以了,很简单吧
<span style="font-family:Microsoft YaHei;">//判断表是否为空表
Status ListEmpty(SqList L)
{
if(L.length == 0)return TRUE;
else return False;
}</span>同样只需要判断length的值是否为0就可以了,很简单
<span style="font-family:Microsoft YaHei;">//销毁表
void DestroyList(SqList &L)
{
free(L.elem);
L.elem = NULL;
L.length = 0;
L.listsize = 0;
} </span>步骤:
①调用free函数释放L,elem指向的内存空间的内存
②将L.elem赋值为NULL,即空指针
③将表的当前长度Length和表的最大长度listsize设置为0
<span style="font-family:Microsoft YaHei;">//获得当前表中元素的数目
int ListLength(SqList L)
{
return L.length;
} </span>直接返回当前长度length即可
<span style="font-family:Microsoft YaHei;">//获得表中第i个元素的值,通过e的值反映
Status GetElem(SqList L,int i,ElemType &e)
{
if(i < 1|| i > L.length)
return ERROR;
e = *(l.elem + i - 1);
return OK;
} </span>①先判断第i个位置是否合法
②将对于位置的值赋值给e,另外减一是因为数组是下标是从0开始的!!
而我们看表是从1开始算的,所以需要减一
<span style="font-family:Microsoft YaHei;">//返回表中第一个满足要求的元素的下标
//这里我们把要求假设为一个函数compare(int l_s,int e);
//参数依次为表中元素与需要进行关系比较的参数e
//第三个参数函数指针,旨锤向函数的指针
int LocateElem(SqList L,ElemType e,Status(*compare)(ElemType,ElemType))
{
int i = 1;
ElemType *p = L.elem;
while(i < L.length && !compare(*p++,e))
i++;
if(i <= L.length) return i;
else return 0;
} </span>代码分析:
步骤:
①定义变量i和指针p分别执行表中第1个元素和表的首地址
②循环调用compare()函数与表中的元素进行比较
③如果i <= length的话说明找到了,返回对应元素的序号
④否则返回0表示找不到
<span style="font-family:Microsoft YaHei;">//返回某个节点的直接前驱
//第二和第三个参数分别为:指定的数据元素,before用来存储它的前驱的
Status PriorElem(SqList L,ElemType choose,ElemType &before)
{
int i = 2;
ElemType *p = L.elem + 1;
while(i <= L.length && *p != choose)
{
p++;
i++;
}
if(i > L.length)return ERROR;
else
{
before = *--p;
return OK;
}
} </span>代码分析:
①首元是没有前驱的,所以i从2,p从L.elem +1 开始算
②通过循环查看指定数据元素在表中的位置,如果i > L.length表示找不到,返回ERROR
③找到的话,通过*--p获取该元素前驱的值赋值给before变量
<span style="font-family:Microsoft YaHei;">//返回某个支点直接后继
//第二三个参数依次为:选定的数据元素的值,存储后继的变量
Status NextElem(SqList L,ElemType choose,ElemType &behind)
{
int i = ;
ElemType *p = L.elem;
while(i < L.length && *p != choose)
{
p++;
i++;
}
if(i == L.length)return ERROR;
else
{
behind = * ++p;
return OK;
}
} </span>①和上面的前驱差不多,要注意的是i == L.length就可以了,因为尾元没有后继,所以直接把尾元排除了!
<span style="font-family:Microsoft YaHei;">//往表的第i个位置插入元素e
Status ListInsert(SqList &L,int i,ElemType e)
{
ElemType *p,*q,*newbase;
//插入位置为1-length,其他值不合法
if(i<1||i>L.length + 1)return ERROR;
//如果表满了的话,增加分配的空间
if(L.length == L.listsize)
{
newbase = (ElemType)realloc(L.elem,(L.listsize + INCREMENT)*sizeof(ElemType));
if(!newbase)exit(ERROR);
L.elem = newbase;
L.listsize += INCREMENT;
}
p = L.elem + i - 1;
//向右移,先移动最后一个
for(q = L.elem + L.length - 1;q >= q;--q)
*(q + 1) = *q;
//将e插入,表长+1
*q = e;
++L.length;
return OK;
} </span>代码解析:
<span style="font-family:Microsoft YaHei;">//删除表中第i个位置的元素
Status ListDelete(SqList &L,int n,ElemType &e)
{
ElemType *p,*q;
//判断删除的位置是否合法
if(i < 1 && i > L.length)return ERROR;
//指向删除的位置,将值付给e
p = L.elem + i - 1;
e = *p;
//指向尾元,由删除位置的后继元素开始前移
q = L.elem + L.length - 1;
for(++p;p <= q;p++)
*(p - 1) = *p;
L.length--;
return OK;
}</span>代码分析:
<span style="font-family:Microsoft YaHei;">//遍历线性表所有元素
void ListTraverse(SqList L,void(*visit)(ElemType&))
{
int i = 1;
ElemType *p = L.elem;
for(i ==1;i <= L.length;i++)
{
visit(*p++);
printf("\n");
}
} </span>代码解析:
代码很简单,就是从第一个元素开始,让指针后移,依次调用visit()函数
实现表中元素的遍历
已知A,B两个顺序表中的元素是按从小到大排列的;现在要你求两个的并集C;
而且C中的元素也要按从小到大排序;不改变A和B中的数据!
是并集哦,就是C中不能有重复的元素
<span style="font-family:Microsoft YaHei;">void UnionList(SqList La,SqList Lb,SqList &Lc)
{
//定义指向La,Lb表头表位的指针,以及指向Lc的指针
ElemType *la,*la_end,*lb,*lb_end,*lc;
la = La.elem;
lb = La.elem;
la_end = La.elem + La.length - 1;
lb_end = Lb.elem + Lb.length - 1;
//在这里为lc分配内存空间,大小为La.length + Lb.length
Lc.listsize = Lc.length = La.length + La.length;
lc = Lc.elem = (ElemType *)malloc(Lc.listsize * sizeof(ElemType));
if(!Lc.elem)exit(ERROR);
//将a,b中的元素进行合并
//如果a,b中都有元素还没有合并
while(la <= la_end && pb <= lb_end)
{
if(*la <= *lb)*lc++ = *la++;
else *lc++ = *lb++;
}
//假如还有剩下的元素,要么是a,要么是b
while(la <= la_end)*lc++ = *la++;
while(lb <= lb_end)*lc++ = *lb++;
//接着要将Lc中重复的元素删除掉
ElemType *p,*q;
p = Lc.elem;
q = p;
//使用两枚指针p,q,如果指针p没有指向末尾
while(p != (Lc.length - 1))
{
//q指向p的后缀,比较两数的值
if(*p != *(++q))
{
p++;
q = p;
}
//相等的话,删除q指向的元素
//再次进行比较,直到不重复为止
else
{
while(*p == *q)
ListDelete(Lc,(p - Lc.elem),e);
}
}
}</span>ps:最后去除Lc中的重复元素的算法似乎有点累赘,如有高效点的算法,欢迎提出,万分感激啊!
①什么是抽象的数据类型ADT
②线性表的定义与线性表的特性
③顺序表:地址连续的存储单元一次存储的线性表
④顺序表的结构,三个基本属性
⑤顺序表的12个相关操作
⑥顺序表的使用小示例
学习资源下载:
本节代码打包:点击下载
数据结构演示工具:点击下载
原文地址:http://blog.csdn.net/coder_pig/article/details/38151653