小猪的数据结构学习笔记(二)
线性表中的顺序表
本节引言:
在上个章节中,我们对数据结构与算法的相关概念进行了了解,知道数据结构的
逻辑结构与物理结构的区别,算法的特性以及设计要求;还学了如何去衡量一个算法
的好坏,以及时间复杂度的计算!在本节中我们将接触第一个数据结构——线性表;
而线性表有两种表现形式,分别是顺序表和链表;学好这一章很重要,是学习后面的基石;
这一节我们会重点学习下顺序表,在这里给大家一个忠告,学编程切忌眼高手低,看懂不代表自己
写得出来,给出的实现代码,自己要理解思路,自己写出来!写多了就有感觉了!多思考!!
另外附上学习数据结构的一个利器,数据结构演示动画,在本文结尾给出!
好了,废话就这么多!
路线图解析:
①抽象数据类型就那三要素:数据,数据之间的关系,和数据的操作
②线性表就是按一条线排列的数据集合,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