概述
线性表是最常用、最简单的数据结构,其主要的特点就是元素间呈现线性关系,即“一个接一个的排列”。一般采用顺序或链式存储。
定义
一个线性表是 n ( n ≥ 0 ) n(n \geq 0) n(n≥0)个元素的有限序列,通常表示为 a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,…,an,其定义如下:
- 存在唯一的“第一个”元素
- 存在唯一的“最后一个”元素
- 除“第一个”元素外,任一元素都只有一个直接前驱
- 除“最后一个”元素外,任一元素都只有一个直接后继
线性表的顺序存储
这是最常用的方式,即用一组地址连续的空间依次存储线性表,在编程中“数组”即是最简单的线性表。
以 L O C ( a 1 ) LOC(a_1) LOC(a1)表示线性表中第一个元素
在顺序存储结构中,第 i i i个元素 a i a_i ai的存储位置为: L O C ( a i ) = L O C ( a 1 ) + ( i − 1 ) × B y t e s ( 每 个 元 素 所 需 空 间 的 字 节 数 ) LOC(a_i) = LOC(a_1) + (i-1) \times Bytes(每个元素所需空间的字节数) LOC(ai)=LOC(a1)+(i−1)×Bytes(每个元素所需空间的字节数)。
可以看出,顺序存储最大的优点即随机存储(Random Access),访问任一位置的元素都可以直接计算出地址,无需额外寻址的过程。
但由于连续的关系,其缺点均体现在删除、插入操作上,这俩操作都需要耗费大量的时间移动元素(以满足顺序存储的特性)。在表长为 n n n的线性表插入元素时,共有 n + 1 n+1 n+1个位置可选,在位置 a 1 a_1 a1插入则需要将整个线性表后移以空出第一位;而在位置 a n + 1 a_{n+1} an+1插入则无需移动任一元素;
定
P
i
P_i
Pi是在第
i
i
i个元素前插入一个元素的概率,
Q
i
Q_i
Qi是删除第
i
i
i个元素的概率,可以假定在线性表任何位置上插入、删除都是等概率的,即:
P
i
=
1
n
+
1
,
Q
i
=
1
n
P_i = \frac{1}{n+1}, \quad Q_i = \frac{1}{n}
Pi=n+11,Qi=n1
每次插入、删除操作需要移动的元素个数期望值
E
i
n
s
e
r
t
、
E
d
e
l
e
t
e
E_{insert}、E_{delete}
Einsert、Edelete如下:
E i n s e r t = ∑ i = 1 n + 1 P i × ( n − i + 1 ) = 1 n + 1 ∑ i = 1 n + 1 ( n − i + 1 ) = n 2 E d e l e t e = ∑ i = 1 n Q i × ( n − i ) = 1 n ∑ i = 1 n ( n − i ) = n − 1 2 \begin{aligned} E_{insert} =& \sum_{i=1}^{n+1} P_i \times (n-i+1) \\ =& \frac{1}{n+1} \sum_{i=1}^{n+1}(n-i+1)\\ =& \frac{n}{2} \\ E_{delete} =& \sum_{i=1}^{n} Q_i \times (n-i)\\ =& \frac{1}{n} \sum_{i=1}^{n} (n-i) \\ =& \frac{n-1}{2} \end{aligned} Einsert===Edelete===i=1∑n+1Pi×(n−i+1)n+11i=1∑n+1(n−i+1)2ni=1∑nQi×(n−i)n1i=1∑n(n−i)2n−1
线性表的链式存储
所谓链式,即存储的实际形式宛如链条,并不是物理上的连续,但逻辑上它仍是线性的,编程中“链表”即其实现。
在链式结构中,以结点为单位存储元素,其结构如下:
其中,数据域存储元素,指针域存储当前结点的前驱或后继结点的位置信息。
链式存储的结点并不要求空间是连续的,因此每个结点都需要额外存储结点之间的逻辑关系。
与顺序存储比较,链式的优点主要有:占用空间灵活,无需连续的地址,当需要一个新的结点时再申请;插入和删除无需移动大量元素,只需要将逻辑上相邻的结点的指针域修改即可;但缺点在于没有随机访问能力,由第一个(头结点)往后逐个访问;其次需要额外的空间保存指针信息;
还有特殊的表现形势如双链表、循环链表等,前者主要优势在于提供了倒序访问能力,但缺点显而易见,需要多保存一个指针。后者则在特殊场景中应用方便,符合逻辑。
其具体的逻辑体现如下图:
图片来自互联网
C语言实现
顺序存储
很早以前学习的时候曾经做过比较完整的基于数组的线性表,但没实现为存储类型无关,供参考,其分为了三个文件:
- Linear_list.c 函数的实现
- Linear_list.h 函数头文件,包含函数功能及其说明
- Linear_list_elemset.h 定义数据类型,用户可在此处定义线性表存储的数据类型
//Linear_list_elemset.h
#ifndef _LINEAR_LIST_ELEMSET_H_
#define _LINEAR_LIST_ELEMSET_H_
#define NAMELEN 20
/*
在下面定义数据域,示例:
typedef int Linear_ElemSet_Data;
or
typedef struct {
int a;
char b;
char Name[20];
} Linear_ElemSet_Data;
*/
typedef struct {
unsigned short Stu_Id;
float Stu_Score[3];
float Stu_Total;
char Name[NAMELEN];
} Linear_ElemSet_Data;
/* 下方为内部实现需要,不能更改 */
typedef struct {
Linear_ElemSet_Data *Elem;
unsigned int List_length;
unsigned int List_pit;
unsigned int List_realloc;
unsigned int List_BufferLen;
} Linear_ElemSet;
typedef Linear_ElemSet LinearList;
typedef Linear_ElemSet_Data LinearListData;
#endif
//Linear_list.h
#ifndef _LINEAR_LIST_H_
#define _LINEAR_LIST_H_
#include "Linear_list_elemset.h"
/*
数据结构 2.1 线性表
建立时间:2015-4-13
概述:
线性表(Linear list)是最常用且最简单的一种数据结构。简言之,一个线性表是n个数据元素的有限序列。
至于每个数据元素的具体含义,在不同的情况下各不相同,它可以是一个数或者是一个符号,也可以是一页
书,甚至其他更复杂的信息。
D={ Ai | Ai∈ElemSet, i=1,2,…,n, n≥0 }
R={ <Ai-1, Ai> | Ai-1, Ai∈D, i=2,…,n }
*/
#define FALSE FALSE
#define TRUE TRUE
typedef enum STATE
{
FALSE, TRUE
}state;
state LINEAR_InitList( Linear_ElemSet *L , int count );
//初始化线性表
//操作结果:构造一个空的线性表L,count为线性表长度阀值(不得低于10),当数据量超出会自动扩展一倍,返回state表示操作是否成功
state LINEAR_DestroyList( Linear_ElemSet *L );
//销毁线性表
//初始条件:线性表L已存在
//操作结果:销毁线性表L,返回state表示操作是否成功
state LINEAR_ClearList( Linear_ElemSet *L );
//重置(清空)线性表
//初始条件:线性表L已存在
//操作结果:将L重置为空表,返回state表示操作是否成功
__inline state LINEAR_ListEmpty( Linear_ElemSet L ) { return L.List_length == 0 ? TRUE: FALSE; }
//检查线性是否为空
//初始条件:线性表L已存在
//操作结果:若L为空表,则返回TRUE,否则返回FALSE
__inline int LINEAR_ListLength( Linear_ElemSet L ) { return L.List_length; }
//返回线性表长度
//初始条件:线性表L已存在
//操作结果:返回L中数据元素个数
state LINEAR_ListEmpty( Linear_ElemSet L );
//检查线性是否为空
//初始条件:线性表L已存在
//操作结果:若L为空表,则返回TRUE,否则返回FALSE
int LINEAR_ListLength( Linear_ElemSet L );
//返回线性表长度
//初始条件:线性表L已存在
//操作结果:返回L中数据元素个数
state LINEAR_GetElem( Linear_ElemSet L, int i, Linear_ElemSet_Data *e );
//获取元素
//初始条件:线性表L已存在,1≤i≤ListLength(L)
//操作结果:用e返回L中第i个数据元素的值。并返回state表示操作是否成功
int LINEAR_LocateElem( Linear_ElemSet L, Linear_ElemSet_Data e, int (*compare)(Linear_ElemSet_Data, Linear_ElemSet_Data) );
//定位元素
//初始条件:线性表L已存在,compare()是数据元素的判定函数(返回0为FALSE,其余为TRUE)
//操作结果:返回L中第1个与e满足关系compare()的数据元素的位序,若这样的数据元素不存在,则返回值为0
state LINEAR_PriorElem( Linear_ElemSet L, int i, Linear_ElemSet_Data *pre_e );
//返回目标元素的前一个元素
//初始条件:线性表L已存在,2≤i≤ListLength(L)
//操作结果:用pre_e返回L中第i个数据元素的前一个元素的值。并返回state表示操作是否成功
state LINEAR_NextElem( Linear_ElemSet L, int i, Linear_ElemSet_Data *next_e );
//返回目标元素的后一个元素
//初始条件:线性表L已存在,1≤i≤( ListLength(L) - 1 )
//操作结果:用next_e返回L中第i个数据元素的后一个元素的值,并返回state表示操作是否成功
int LINEAR_ListAddElem( Linear_ElemSet *L, Linear_ElemSet_Data e );
//为线性表添加一个元素
//初始条件:线性表L已存在
//操作结果:在L中的尾部插入一个新的数据元素e,L的长度加1。并返回添加后线性表长度
state LINEAR_ListInsert( Linear_ElemSet *L, int i, Linear_ElemSet_Data e );
//为线性表插入一个元素
//初始条件:线性表L已存在,1≤i≤( ListLength(L) +1 )
//操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1。并返回state表示操作是否成功
state LINEAR_ListDelete( Linear_ElemSet *L, int i, Linear_ElemSet_Data *e );
//为线性表删除一个元素
//初始条件:线性表L已存在且非空,1≤i≤ListLength(L)
//操作结果:删除L的第i个元素,并用e返回被删除元素的值,L的长度减1。并返回state表示操作是否成功
state LINEAR_ListElemCover( Linear_ElemSet *L, int i, Linear_ElemSet_Data *e );
//对线性表一个指定元素执行覆盖
//初始条件:线性表已存在且非空,1≤i≤ListLength(L)
//操作结果:使用e覆盖L的第i个元素,返回state表示操作是否成功
state LINEAR_ListTraverse( Linear_ElemSet L, int (*visit)(Linear_ElemSet_Data) );
//历遍线性表
//初始条件:线性表L已存在且非空
//操作结果:依次对线性表里的每一个数据元素执行visit()函数,一旦visit返回0(FALSE),则操作失败。并返回state表示操作是否成功
#endif
//Linear_list.c
#include "Linear_list.h"
#include <malloc.h>
#include <stdio.h>
static state LINEAR_ReallocList( Linear_ElemSet *L )
{
Linear_ElemSet_Data *pNew = ( Linear_ElemSet_Data *) realloc( (*L).Elem, sizeof(Linear_ElemSet_Data) * ( (*L).List_pit + (*L).List_pit * (*L).List_realloc ) );
if( pNew == NULL )
return FALSE;
(*L).Elem = pNew;
(*L).List_BufferLen += (*L).List_pit;
(*L).List_realloc++;
return TRUE;
}
state LINEAR_InitList( Linear_ElemSet *L , int count )
{
(*L).List_length = 0;
(*L).List_pit = count;
(*L).List_realloc = 1;
(*L).List_BufferLen = count;
if( count < 10 )
{
fprintf( stderr, "LINEAR_InitList Function Error\n" );
fprintf( stderr, "the List Pit can't lower than 10\n" );
return FALSE;
}
if( ( (*L).Elem = ( Linear_ElemSet_Data *) malloc( sizeof(Linear_ElemSet_Data) * (*L).List_pit ) ) == NULL )
{
fprintf( stderr, "LINEAR_InitList Function Error\n" );
fprintf( stderr, "Can't allocate Memory!\n" );
return FALSE;
}
return TRUE;
}
//初始化线性表
//操作结果:构造一个空的线性表L,count为线性表长度阀值(不得低于10),当数据量超出会自动扩展一倍,返回state表示操作是否成功
state LINEAR_DestroyList( Linear_ElemSet *L )
{
if( (*L).Elem == NULL )
{
fprintf( stderr, "LINEAR_DestroyList Function Error\n" );
fprintf( stderr, "This Linear has been free!\n" );
return FALSE;
}
free( (*L).Elem );
(*L).List_length = 0;
return TRUE;
}
//销毁线性表
//初始条件:线性表L已存在
//操作结果:销毁线性表L,返回state表示操作是否成功
state LINEAR_ClearList( Linear_ElemSet *L )
{
if( LINEAR_ListEmpty(*L) )
{
fprintf( stderr, "LINEAR_ClearList Function Error\n" );
fprintf( stderr, "The Linear is emtpy!\n" );
return FALSE;
}
(*L).List_length = 0;
return TRUE;
}
//重置(清空)线性表
//初始条件:线性表L已存在
//操作结果:将L重置为空表,返回state表示操作是否成功
state LINEAR_GetElem( Linear_ElemSet L, int i, Linear_ElemSet_Data *e )
{
if( LINEAR_ListEmpty(L) || i > LINEAR_ListLength(L) || i <= 0 )
{
fprintf( stderr, "LINEAR_GetElem Function Error\n" );
fprintf( stderr, "Out of bound! List length is %d, i is %d\n", LINEAR_ListLength(L), i );
return FALSE;
}
*e = L.Elem[i-1];
return TRUE;
}
//获取元素
//初始条件:线性表L已存在,1≤i≤ListLength(L)
//操作结果:用e返回L中第i个数据元素的值。并返回state表示操作是否成功
int LINEAR_LocateElem( Linear_ElemSet L, Linear_ElemSet_Data e, int (*compare)(Linear_ElemSet_Data, Linear_ElemSet_Data) )
{
int i;
if( LINEAR_ListEmpty(L) )
{
fprintf( stderr, "LINEAR_LocateElem Function Error\n" );
fprintf( stderr, "The Linear is empty!\n" );
return FALSE;
}
for( i = 0; i < LINEAR_ListLength(L); i++ )
{
if( compare( L.Elem[i], e ) != FALSE )
return i+1;
}
return 0;
}
//定位元素
//初始条件:线性表L已存在,compare()是数据元素的判定函数(返回0为FALSE,其余为TRUE)
//操作结果:返回L中第1个与e满足关系compare()的数据元素的位序,若这样的数据元素不存在,则返回值为0
state LINEAR_PriorElem( Linear_ElemSet L, int i, Linear_ElemSet_Data *pre_e )
{
if( LINEAR_ListEmpty(L) || i > LINEAR_ListLength(L) || i <= 1 )
{
fprintf( stderr, "LINEAR_PriorElem Function Error\n" );
fprintf( stderr, "Out of bound! List length is %d, i is %d\n", LINEAR_ListLength(L), i );
return FALSE;
}
*pre_e = L.Elem[i-2];
return TRUE;
}
//返回目标元素的前一个元素
//初始条件:线性表L已存在,2≤i≤ListLength(L)
//操作结果:用pre_e返回L中第i个数据元素的前一个元素的值。并返回state表示操作是否成功
state LINEAR_NextElem( Linear_ElemSet L, int i, Linear_ElemSet_Data *next_e )
{
if( LINEAR_ListEmpty(L) || i >= LINEAR_ListLength(L) || i <= 0 )
{
fprintf( stderr, "LINEAR_NextElem Function Error\n" );
fprintf( stderr, "Out of bound! List length is %d, i is %d\n", LINEAR_ListLength(L), i );
return FALSE;
}
*next_e = L.Elem[i];
return TRUE;
}
//返回目标元素的后一个元素
//初始条件:线性表L已存在,1≤i≤( ListLength(L) - 1 )
//操作结果:用next_e返回L中第i个数据元素的后一个元素的值,并返回state表示操作是否成功
state LINEAR_ListInsert( Linear_ElemSet *L, int i, Linear_ElemSet_Data e )
{
int j;
if( LINEAR_ListLength(*L) >= (*L).List_BufferLen )
{
if( LINEAR_ReallocList(L) == FALSE )
{
fprintf( stderr, "LINEAR_ListInsert Function Error\n" );
fprintf( stderr, "Can't realloc the memory! list length is %d, list buffer len is %d\n", LINEAR_ListLength(*L), (*L).List_BufferLen );
fprintf( stderr, "Cancle the Insert opeartion!\n" );
return FALSE;
}
}
if( LINEAR_ListEmpty(*L) || i > LINEAR_ListLength(*L) || i<= 0 )
{
fprintf( stderr, "LINEAR_ListInsert Function Error\n" );
fprintf( stderr, "Can't insert in that postion! Listlength is %d, i is %d\n", LINEAR_ListLength(*L), i );
return FALSE;
}
for( j=LINEAR_ListLength(*L); j>=i; j-- )
{
(*L).Elem[j] = (*L).Elem[j-1];
}
(*L).Elem[i-1] = e;
(*L).List_length++;
return TRUE;
}
//为线性表插入一个元素
//初始条件:线性表L已存在,1≤i≤( ListLength(L) +1 )
//操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1。并返回state表示操作是否成功
int LINEAR_ListAddElem( Linear_ElemSet *L, Linear_ElemSet_Data e )
{
if( LINEAR_ListLength(*L) >= (*L).List_BufferLen )
{
if( LINEAR_ReallocList(L) == FALSE )
{
fprintf( stderr, "LINEAR_ListAddElem Function Error\n" );
fprintf( stderr, "Can't realloc the memory! list length is %d, list buffer len is %d\n", LINEAR_ListLength(*L), (*L).List_BufferLen );
fprintf( stderr, "Cancle the Add opeartion!\n" );
return LINEAR_ListLength(*L);
}
}
(*L).Elem[LINEAR_ListLength(*L)] = e;
++(*L).List_length;
return LINEAR_ListLength(*L);
}
//为线性表添加一个元素
//初始条件:线性表L已存在
//操作结果:在L中的尾部插入一个新的数据元素e,L的长度加1。并返回state表示操作是否成功
state LINEAR_ListDelete( Linear_ElemSet *L, int i, Linear_ElemSet_Data *e )
{
int j;
if( LINEAR_ListEmpty(*L) || i > LINEAR_ListLength(*L) || i<= 0 )
{
fprintf( stderr, "LINEAR_ListDelete Function Error\n" );
fprintf( stderr, "Can't delete in that postion! Listlength is %d, i is %d\n", LINEAR_ListLength(*L), i );
return FALSE;
}
*e = (*L).Elem[i-1];
for( j=i; j<LINEAR_ListLength(*L); j++ )
{
(*L).Elem[j-1] = (*L).Elem[j];
}
(*L).List_length--;
return TRUE;
}
//为线性表删除一个元素
//初始条件:线性表L已存在且非空,1≤i≤ListLength(L)
//操作结果:删除L的第i个元素,并用e返回被删除元素的值,L的长度减1。并返回state表示操作是否成功
state LINEAR_ListElemCover( Linear_ElemSet *L, int i, Linear_ElemSet_Data *e )
{
if( LINEAR_ListEmpty(*L) || i > LINEAR_ListLength(*L) || i<= 0 )
{
fprintf( stderr, "LINEAR_ListElemCover Function Error\n" );
fprintf( stderr, "Can't Cover in that postion! Listlength is %d, i is %d\n", LINEAR_ListLength(*L), i );
return FALSE;
}
(*L).Elem[i] = *e;
return TRUE;
}
//对线性表一个指定元素执行覆盖
//初始条件:线性表已存在且非空,1≤i≤ListLength(L)
//操作结果:使用e覆盖L的第i个元素,返回state表示操作是否成功
state LINEAR_ListTraverse( Linear_ElemSet L, int (*visit)(Linear_ElemSet_Data) )
{
int i;
if( LINEAR_ListEmpty(L) )
{
fprintf( stderr, "LINEAR_ListTraverse Function Error\n" );
fprintf( stderr, "List is empty!\n" );
return FALSE;
}
for( i=0; i<LINEAR_ListLength(L); i++ )
{
if( visit(L.Elem[i]) == FALSE )
{
fprintf( stderr, "Visit Error in %d element!\n", i+1 );
return FALSE;
}
}
return TRUE;
}
//历遍线性表
//初始条件:线性表L已存在且非空
//操作结果:依次对线性表里的每一个数据元素执行visit()函数,一旦visit返回0(FALSE),则操作失败。并返回state表示操作是否成功
链式存储
采用的简单单链表及无头结点实现,有两个文件。实际上通过设计一个头结点会使得代码更简单易懂,并且对链表的维护更容易。
//Link_list.h
#ifndef _LINK_LIST_H_
#define _LINK_LIST_H_
#include <stdio.h>
#include <malloc.h>
typedef struct {
int data;
struct LLNode *Next;
}LLNode, *LLHead;
typedef int DataType;
/*
初始化LLHead。
*/
void LL_Initialize(LLHead *p);
/*
插入元素:将elem插入到pos的位置(0为第一位)
初始条件:p已初始化,pos为有效位置(≥0,若大于链表长度不论为多少默认为最后)
操作结果:成功返回1,否则返回0
*/
int LL_Insert(LLHead *p, int pos, DataType elem);
/*
删除元素:删除pos位置的元素
初始条件:p已初始化,pos为有效位置(≥0且≤链表长度-1)
操作结果:成功返回1,否则返回0
*/
int LL_Delete(LLHead *p, int pos);
/*
查找元素:查找elem元素的位置
初始条件:p已初始化
操作结果:若元素存在于链表中,返回位置pos;否则返回-1
*/
int LL_Find(LLHead p, DataType elem);
/*
查找元素:查找位于pos的元素
初始条件:p已初始化,pos为有效位置(≥0且≤链表长度-1)
操作结果:若pos有效,将修改outElem中内容为该位置元素并返回1;否则返回0。
*/
int LL_FindAt(LLHead p, int pos, DataType *outElem);
#endif
//Link_list.c
#include "Link_list.h"
static LLNode* NewNode(DataType dat, LLNode *next)
{
LLNode *p = malloc(sizeof(LLNode));
if (p == NULL)
{
fprintf(stderr, "Can't allocate memory!");
return NULL;
}
p->data = dat;
p->Next = next;
return p;
}
void LL_Initialize(LLHead * p)
{
*p = NULL;
}
//由于该链表不存在单独的头结点,LLHead是指向头结点的指针变量,插入或删除有时候需要修改头指针变量,因此参数为LLHead *。
int LL_Insert(LLHead * p, int pos, DataType elem)
{
if (pos < 0)
return 0;
LLNode *pcur = *p;
LLNode *prev = NULL; //保留前继指针方便修改
if (pcur == NULL) //当p为NULL意味着是一个新的链表,直接插入并修改头指针
*p = NewNode(elem, NULL);
else if (pos == 0) //当pos为0时意味着插入到链表头,同样直接插入并修改头指针
*p = NewNode(elem, pcur);
else
{
while (pcur != NULL && pos-- >= 0) //循环完毕后要么已经到了链表的尾部,要么到达了pos的位置
{
prev = pcur;
pcur = pcur->Next;
}
prev->Next = NewNode(elem, pcur);
}
return 1;
}
int LL_Delete(LLHead * p, int pos)
{
if (*p == NULL)
{
fprintf(stderr, "Empty List!");
return 0;
}
if (pos == 0) //如若删除链表第一个,则需要修改头指针
{
*p = (*p)->Next;
return 1;
}
LLNode *pcur = *p;
LLNode *prev = NULL;
while (pcur != NULL && pos-- >= 0)
{
prev = pcur;
pcur = pcur->Next;
}
if (pos >= 0) //如果pos仍然≥0,则说明pos长度大于链表最大长度。
{
fprintf(stderr, "Out of Bound!");
return 0;
}
//删除第n位链表结点,实际上就是使第n-1位结点指向n+1位结点。
prev->Next = pcur->Next;
free(pcur);
return 1;
}
int LL_Find(LLHead p, DataType elem)
{
if (p == NULL)
{
fprintf(stderr, "Empty List!");
return 0;
}
int pos = 0;
while (p != NULL)
{
if (p->data == elem)
return pos;
pos++;
p = p->Next;
}
//循环结束如果尚未返回证明链表中不存在该元素
return -1;
}
int LL_FindAt(LLHead p, int pos, DataType *outElem)
{
if (p == NULL)
{
fprintf(stderr, "Empty list!");
return 0;
}
if (outElem == NULL)
{
fprintf(stderr, "outElem is NULL!");
return 0;
}
if (pos < 0)
{
fprintf(stderr, "Out of Bound!");
return 0;
}
while (p != NULL && pos-- > 0)
p = p->Next;
if (pos >= 0)
{
fprintf(stderr, "Out of Bound!");
return 0;
}
*outElem = p->data;
return 1;
}