【黑马程序员-学习笔记】数据结构-顺序表

来源:互联网 发布:如何查看网络是否稳定 编辑:程序博客网 时间:2024/04/27 13:22

一、存储

线性表的顺序存储是指在内存中用地址连续的一块存储空间顺序存放线性表的各元素,用这种存储形式存储的线性表称其为顺序表。因为内存中的地址空间是线性的,因此,用物理上的相邻实现数据元素之间的逻辑相邻关系是既简单,又自然的。如图2.1 所示。


设a1的存储地址为Loc(a1),每个数据元素占d个存储地址,则第i个数据元素的地为:
Loc(ai)=Loc(a1)+(i-1)*d 1<=i<=n

这就是说只要知道顺序表首地址和每个数据元素所占地址单元的个数就可求出第i个数据元素的地址来,这也是顺序表具有按数据元素的序号随机存取的特点。

在程序设计语言中,一维数组在内存中占用的存储空间就是一组连续的存储区域,因此,用一维数组来表示顺序表的数据存储区域是再合适不过的。考虑到线性表的运算有插入、删除等运算,即表长是可变的,因此,数组的容量需设计的足够大,设用:data[MAXSIZE]来表示,其中MAXSIZE是一个根据实际问题定义的足够大的整数,线性表中的数据从data[0] 开始依次顺序存放,但当前线性表中的实际元素个数可能未达到MAXSIZE多个,因此需用一个变量last 记录当前线性表中最后一个元素在数组中的位置,即last 起一个指针的作用,始终指向线性表中最后一个元素,因此,表空时last=-1。这种存储思想的具体描述可以是多样的。如可以是:
datatype data[MAXSIZE];
int last;

这样表示的顺序表如图2.1 所示。表长为last+1,数据元素分别存放在data[0]到data[last]中。这样使用简单方便,但有时不便管理。
从结构性上考虑,通常将data 和last 封装成一个结构作为顺序表的类型:
typedef struct
{ datatype data[MAXSIZE];
int last;
} SeqList;

定义一个顺序表:SeqList L ;
这样表示的线性表如图2.2(a) 所示。表长=L.last+1,线性表中的数据元素a1至an分别存放在L.data[0]至L.data[L.last]中。由于我们后面的算法用C语言描述,根据C语言中的一些规则,有时定义一个指向SeqList 类型的指针更为方便:
SeqList *L ;
L是一个指针变量,线性表的存储空间通过L=malloc(sizeof(SeqList)) 操作来获得。L中存放的是顺序表的地址,这样表示的线性表如图2.2(b)所示。表长表示为(*L).last或L->last+1,线性表的存储区域为L->data ,线性表中数据元素的存储空间为:
L->data[0] ~ L->data[L->last]。

在以后的算法中多用这种方法表示,读者在读算法时注意相关数据结构的类型说明。

二、基本运算

1.顺序表的初始化

顺序表的初始化即构造一个空表,这对表是一个加工型的运算,因此,将L设为指针参数,首先动态分配存储空间,然后,将表中last 指针置为-1,表示表中没有数据元素。算法如下:
SeqList *init_SeqList( )
{ SeqList *L;
L=malloc(sizeof(SeqList));
L->last=-1; return L;
}

设调用函数为主函数,主函数对初始化函数的调用如下:
main()
{SeqList *L;
L=Init_SeqList();
...
}

2. 插入运算

算法如下:
int Insert_SeqList(SeqList *L,int i,datatype x)
{ int j;
if (L->last==MAXSIZE-1)
{ printf("表满"); return(-1); } /*表空间已满,不能插入*/
if (i<1 || i>L->last+2) /*检查插入位置的正确性*/
{ printf("位置错");return(0); }
for(j=L->last;j>=i-1;j--)
L->data[j+1]=L->data[j]; /* 结点移动*/
L->data[i-1]=x; /*新元素插入*/
L->last++; /*last仍指向最后元素*/
return (1); /*插入成功,返回*/
}

3. 删除运算DeleteList(L,i)

算法如下:
int Delete_SeqList(SeqList *L;int i)
{ int j;
if(i<1 || i>L->last+1) /*检查空表及删除位置的合法性*/
{ printf ("不存在第i个元素"); return(0); }
for(j=i;j<=L->last;j++)
L->data[j-1]=L->data[j]; /*向上移动*/
L->last--;
return(1); /*删除成功*/
}

4. 按值查找

算法如下:
int Location_SeqList(SeqList *L, datatype x)
{ int i=0;
while(i<=L.last && L->data[i]!= x)
i++;
if (i>L->last) return -1;
else return i; /*返回的是存储位置*/

}

三、单链表

存放数据元素信息的称为数据域,存放其后继地址的称为指针域。因此n个元素的线性表通过每个结点的指针域拉成了一个“链子”,称之为链表。因为每个结点中只有一个指向后继的指针,所以称其为单链表。
链表是由一个个结点构成的,结点定义如下:
typedef struct node
{ datatype data;
struct node *next;
} LNode,*LinkList;

定义头指针变量:

                                                                                                                            

四、循环链表

对两个单循环链表H1 、H2 的连接操作,是将H2 的第一个数据结点接到H1 的尾结点,如用头指针标识,则需要找到第一个链表的尾结点,其时间复杂性为O(n),而链表若用尾指针R1 、R2 来标识,则时间性能为O(1)。操作如下:
p= R1 –>next; /*保存R1 的头结点指针*/
R1->next=R2->next->next; /*头尾连接*/
free(R2->next); /*释放第二个表的头结点*/
R2->next=p; /*组成循环链表*/

这一过程可见图2.17。



0 0
原创粉丝点击