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

数据结构(第二课)--线性表

2014-11-05 20:14 246 查看
数据结构,之前感觉不到其重要性,线性表对我们以后的编程会有什么帮助呢,今天看到关于一个java方面的问题才发现其重要性,在java中,我们所用到的集合list等,都是通过线性表来实现的,了解了线性表,我们对这些的理解会更深入,用起来会更加的得心应手,程序中的数据大致分为四种姐帮你的逻辑结构,集合,线性结构,树形结构,图状结构或网状结构,对于数据的不同逻辑结构,计算机在物理磁盘上通常有点2中方式,一个是链式存储结构,一种是顺序存储结构。

线性表是线性结构中最常用的数据结构。

顺序存储结构:

线性表的顺序存储结构是用一组地址连续的存储单元一次存放线性表的元素,因此线性表中的数据元素逻辑上和物理存储的关系是一致的,程序获取该数据的地址的时间和获取该数据所用的时间是相同的,因为每个元素的存储都是紧挨着的,而每一个元素的长度也是相同的,所以我们可以根据其地址很容易的找到这个元素,所以说是做到了随机的存取,这也是顺序存储的一个优点。顺序结构的存储底层是通过数组来实现的,我们在存储的时候就和我们在数组中存放数值是一样的,所以说当对其进行插入,删除操作的时候,我们可能要移动一般的数据,这样的效率是比较低的。

链式存储结构:

链式存储结构是采用一组地址任意的存储单元来存放 线性表中的元素,链式结构的线性表会按照线性的逻辑顺序来保存数组元素而在每一个数据元素中保存一个下一个元素的引用,由于不是按照顺序结构来写的,所以在我们用其执行查找操作的时候,是比较麻烦的,因为要遍历每一个元素,通过每一个元素的引用去寻找下一个,然后依次进行。但是由于每一个元素都要保存下一个元素的地址,这也无疑增大了内存的开销,但是对其执行删除,插入的操作的时候是比较方便的,我们只需要去找到这个位置,通过改变其引用的指向就可以了而不需要移动每一个元素。

线性表的链式表示和实现

//  初始化一个线性表
Status InitList Sq (SqList &L){
	L.elem = (ElemType * )malloc (LIST INIT SIZE * sizeof (ElemType));
	if (!L.elem)
		exit (OVERFLOW);
	L.length = 0;
	L.listsize = LIST INIT SIZE;
	return OK;
}
//顺序结构的线性表中添加一个元素的方法
Status ListInsert _Sq(SqList &L, int i, ElemType e){
	if (i < 1 || i > L.length + 1)
		return false;
	if (L.length > L.listsize){
		newbase = (ElemType *) relloc (L.elem (L.listsize+ LISTINCREATMENT)*sizeof(ElemType));
		L.elem = newbase;
		L.listsize + = LISTINCREATEMENT;
		if (! newbase)
			exit (StakOverFlow);
	}
	q = & (L.elem[i-1];
	for (p = &(L.elem[L.length-1]; p >= q; p--)
		*p = *(p+1);
	*q = e;
	++ L.length;
}
//顺序结构的删除方式
Status ListDelete (Sqlist &L, int i,ElemType &e){
	if (i < 1 || i > L.length + 1)
		return false;
	p  =  &(L.elem[i-1]);
	e = *p;
	q = L.length;
	for (++p; p < =q; p++){
		*(p-1) = *p;
	}
	--L.length;
	return OK;
}


顺序表中的两个表的合并

//将两个线性表的元素进行合并
void union (List &a, List b){
	a.len = ListLength (a);
	b.len = ListLength (b);
	for(i = 1; i < b.len; i++){
		GetElem(b, i, e);
		if(!LocateElem(a, e, equal))
			ListInsert(a, a.len++, e);
	}
}
//将之前排好顺序的线性表中再插入数据,此处假设数据按升序排列
void mergList (List a, List b, List &c){
	a.len = ListLength (a);
	b.len = ListLength (b);
	i = j = 1;
	k = 0;
	while (i <= a.len && j <= b.len){
		GetElem (a, i, ai);
		GetElem (b, j, bj);
		if(ai < bj){
			ListInsert (c, k++; ai);
			i++;
		}
		else {
			ListInsert (c, k++; bj);
			j++;
	}
	while (i <= a.len){
		GetElem (a, i, ai);
		ListInsert (a, i, ai);
		i++;
	}
	while (j <= b.lem){
		GetElem (b, j, bi);
		ListInsert (b, j, bj);
		j++;
	}
}


线性表的链式表示涉及到的一些算法

//链式表获取元素
Status GetElem (LinkList L, int i, ElemType &e){
	p = L->next; j = 1;
	if (!p || i < j)
		return error;
	while (p && j < i){
		p = p->next;
		++ j;
	}
	e = p -> data;
	return OK;
}
//单链表中插入数据
Status ListInsert (LinkList & L, int i, ElemType e){
	p = L->next; j = 1;
	if (!p || i < j)
		return error;
	while (p && i > j){
		p = p->next;
		++ j;
	}
	s = (LinkList) malloc (sizeof(LNode));
	s -> data = p -> data;
	s -> next = p ->next;
	p ->next = s;
	return OK; 
}
//单链表中删除数据
Status ListDelete (LinkList & L, int i, ElemType & e){
	p = L->next; j = 1;
	if(!p || i < j)
		return error;
	while (p && i > j){
		p = p ->next;
		++ j;
	}
	q = p->next;
	p  = q->next;

}
线性表的链式表示又有这么几种,一个是循环链表,一个是双向链表,循环链表就是最后一个节点的后继指向的是第一个结点,这样当查找一个结点的时候可以从任何一个结点开始都是可以的,双向链表就是每一个节点存在一个前驱,也就是每个节点有两个指针域,一个指向前面,也就是它的前驱,另一个指向的是它的后继。双向链表在插入节点和删除节点的时候是比较麻烦的。

线性表的应用:

一元多项式的相加

解决一元多项式相加的问题,我们可以通过线性表来模拟实现,顺序表模拟,每一个表的位置代表指数,表中的数值代表的是系数,链表模拟的话,为每一个结点增加一个数据域,一个数据域用来保存系数,一个用来保存指数,这样,通过顺序表保存的话会造成空间上的浪费,通过链式表来实现可以最大限度的充分利用空间。

利用链式表来实现相加的话,也就是两个表的合并,将第一个链表的元素和第二个元素进行比较,如果第二链表中的结点有和这个结点的指数相同的,就将这两个结点的系数相加,然后将其和作为第二个链表中系数存放,如果没有和这个结点相同的,就将该结点家在第二个链表的后面。通过这来完成多项式的相加。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: