线性表是最简单的数据结构,其主要特征有:
1、 每个线性表只有一个头元素,一个尾元素;
2、 除第一个数据元素外,每个元素都有一个直接前驱;
3、 除最后一个数据元素外,每个元素都有一个直接后继。
一、 顺序表
顺序表是用数据元素在物理上的相邻表示逻辑上的相邻。顺序表具有随机存取的特性。
用动态分配的一位数组表示顺序表如下:
初始化顺序表:
Status InitList_Seq(SqList &L) { L.elem = (ElemType*)malloc(LIST_NINT_SIZE*sizeof(ElemType)); if(!L.elem) exit(OVERFLOW); L.length = 0; L.lisesize = LIST_INIT_SIZE; return OK; }
顺序表的插入:
Status ListInsert_Seq(SqList &L, int i, ElemType e) { if(i < 1 || i > L.length + 1) return ERROR; if(L.length >= L.listsize) { newbase = (ElemType*)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType)); if(!newbase) exit(OVERFLOW); L.elem = newbase; L.listsize += LISTINCREMENT; } q = &(L.elem(i-1)); for(p = &(L.elem[L.length-1]); p >= q;p--) *(p+1) = *p; *q = e; L.length++; return OK; }
顺序表的删除:
Status ListDelete_Seq(SqList &L, int i, ElemType &e) { if(i < 1 || i > L.length) return ERROR; p = &L.elem[i-1]; e = *p; for(q = L.elem+L.length-1; p < q; p++) *p = *(p+1); L.length--; return OK; }
从以上伪码可知,在顺序表中插入或删除一个元素,需要移动多个元素。对于插入,Ei = n/2; 对于删除, Ed = (n-1)/2。
二、单链表
和顺序表不同,单链表是用指针来表示数据元素之间的关系。单链表的每个结点包含两个域:一个数据域,用来存储数据元素的信息;一个指针域,用来存储后续节点的位置信息。数据元素之间的逻辑关系是用指针来表示的。逻辑上相邻的数据元素,在物理上不一定是相邻的。这样的存储结构便失去了随机存取的特性。但他的优点是插入和删除结点的时候不需要移动数据元素了。
线性表的单链表存储结构
typedef struct LNode{ ElemType data; struct Lnode *next; }LNode, *LinkList;
单链表中插入一个结点:
Status ListInsert_L(LinkList &L, int i, ElemType e) { p = L; j = 0; while(p && j < i-1) { p = p->next; j++; } if(!p || j > i-1) return ERROR; s = (LinkList)malloc(sizeof(LNode)); s->data = e; s->next = p->next; p->next = s; return OK; }
单链表中删除一个元素结点:
Status ListDelete_L(LinkList &L, int i, ElemType &e) { p = L; j = 0; while(p && j < i-1) { p = p->next; j++; } if(!p || j > i-1) return ERROR; q = p->next; e = q->data; p->next = q->next; free(q); return OK; }
虽然单链表中插入和删除元素不需要移动元素了,但是获取第i个元素,却需要从头开始找起:
Status GetElem_L(LinkList L, int i, ElemType &e) { p = L->next; j = 1; while(p && j < i) { p = p ->next; j++; } if(!p || j > i) return ERROR; e = p->data; return OK; }
在没有指针的编程语言中,我们可以用一维数组来表示线性链表——静态链表:
#define MAXSIZE 100 typedef struct{ ElemType data; int cur; }component, SLinkList[MAXSIZE];
三、双向链表
由于单链表中某些操作较为复杂,例如,PriorElem的执行时间为O(n),为了克服这种单向性的缺点,可以为每个结点设置两个指针域,一个指向后续结点,一个指向前驱结点,即双向链表。
typedef struct DuLNOde{ ElemType data; struct DuLNode *prior; struct DuLNode *next; }DuLNode, *DuLinkList;
双向链表的特性: d->next->prior = d->prior->next = d;
四、循环链表
循环链表是另外一种链式存储结构。其特点是表中最后一个结点的指针域又指向了头结点,使整个链表形成了一个环形。从任何一个结点出发都可以遍历表中的所有结点。有的时候,在循环链表中设立尾指针比设立头指针更方便。例如,合并两个链表的时候,如果有尾指针的话,合并操作将会非常简单。
来源:https://www.cnblogs.com/uilotus/p/3498663.html