首页 > 代码库 > 线性表
线性表
1.线性表相关定义:
线性表为a1,…,ai-1,ai,ai+1,…,an,则ai-1为ai的直接前驱元素,ai+1为ai的直接后驱元素。当i=1,2…,n-1时,ai有且仅有一个直接后驱;当i=2,3,…,n时,ai有且仅有一个直接前驱。即元素是有顺序的,第一个元素无前驱,最后一个元素无后驱,其他每个元素有且仅有一个前驱和后驱。
线性表元素个数定义线性表长度,n=0时称为空表。
2.顺序存储结构:
用一段地址连续的存储单元依次存储线性表的数据元素。
属性:起始位置、最大存储容量(数组长度)、线性表当前长度
注:线性表长度应小于等于数组长度
一个有趣的例子:图书馆占位。占了10个位置(数组长度),但来的人可以<=10,不可以>10。
1)读取第i个数据
直接返回数组下标为i-1的元素
2)在第i个位置插入新元素e
从最后一个元素遍历到第i个元素,分别将它们向后移动一个位置。然后将新元素e插入到第i个位置
3)删除第i个元素
从删除元素位置开始遍历到最后一个元素,分别讲它们向前移动一个位置
时间复杂度:
最好的情况,i=n,则不需移动其他元素,时间复杂度为O(1)
最坏的情况,i=1,则所有元素都需移动,时间复杂度为O(n)
#include <iostream> using namespace std; //顺序存储 #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define MAXSIZE 20 typedef int elemtype; typedef struct{ elemtype data[MAXSIZE]; int length; }sqlist; typedef int status; //读取 status getelem(sqlist L,int i,elemtype *e){ if(L.length==0||i<1||i>L.length) return ERROR; *e=L.data[i-1]; return OK; } //插入 status linsert(sqlist *L,int i,elemtype e){ int k; if (L->length==MAXSIZE)//当前线性表长度不能超过数组长度,否则不能插入 return ERROR; if(i<1||i>L->length) return ERROR; if(i<L->length) { for(k=L->length-1;k>=i-1;k--) L.data[k+1]=L.data[k]; } L.data[i-1]=e; L->length++; return OK; } //删除 status ldelete(sqlist *L,int i,elemtype *e){ if(L->length==0)//当前线性表不能为空,否则不能删除 return ERROR; if(i<1||i>L->length) return ERROR; *e=L->data[i-1]; if(i<L->length){ for(k=i;k<=L->length-1;k++) L->data[k-1]=L->data[k]; } L->length--; return OK; } int main(int argc, char** argv) { return 0; }
3.链式存储结构:
对数据元素ai,除存储其本身信息外,还需存储一个指示其直接后继的信息。数据域与指针域组成数据元素ai的存储映像,称为结点node。
n个结点链结成一个链表,由于每个结点中只包含一个指针域,称为单链表。
第一个结点的存储位置为头指针,之后的每一个结点就是上一个的后继指针指向的位置。规定最后一个结点指针为空(用NULL或^表示)
有时,会在一个结点前加一个头结点,数据域可以不存储信息。
1)读取第i个数据
声明一个指针指向链表第1个结点,遍历链表,让指针向后移动不断指向下一节点,直到第i个结点。
2)第i个数据插入结点s
先找到第i个数据,s->next=p->next;p->next=s;
3)第i个数据删除结点s
先找到第i个数据,s=p->next;p->next=s-next;即p->next=p->next->next
#include <iostream> using namespace std; //单链表 #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define MAXSIZE 20 typedef int elemtype; typedef int status; typedef struct node{ elemtype data; struct node *next; }node; typedef struct node *linklist;//链表的构建不同于顺序结构的数组初始化 //链表的构建就是一个动态生成链表的过程。即从空表的初始状态起,依次建立各元素结点并插入链表 void createlisthead(linklist *L,int n){ linklist p; int i; srand(time(0)); *L=(linklist)malloc(sizeof(node));// (*L)->next=NULL; for (i=0;i<n;i++){ p=(linklist)malloc(sizeof(node)); p->data=http://www.mamicode.com/rand()%100+1; p->next=(*L)->next; (*L)->next=p;//典型的单链表插入操作哦 } } //读取 status getelem(linklist L,int i,elemtype *e){ int j; linklist p; p=L->next;//P指向L的第1个结点 j=1; while(p&&j<i){ p=p->next; ++j; } if(!p||j>1) return ERROR; *e=p->data; return OK; } //插入 status linsert(linklist *L,int i,elemtype e){ int j; linklist p,s; p=*L; j=1; while(p&&j<i){ p=p->next; ++j; } if(!p||j>1) return ERROR; s=(linklist)malloc(sizeof(node)); s->data=http://www.mamicode.com/e; s->next=p->next; p->next=s; return OK; } //删除 status ldelete(linklist *L,int i,elemtype e){ int j; linklist p,s; p=*L; j=1; while(p&&j<i){ p=p->next; ++j; } if(!p||j>1) return ERROR; s=p->next; p->next=s->next; *e=s->data; free(s); return OK; } //整表删除 status clearlist(linklist *L){ linklist p,q; p=(*L)->next; while(p){ q=p->next; free(p); p=q; } (*L)->next=NULL; return OK; }
4.链表之静态链表:
用数组描述链表:由两个数组域组成,data\cur。
将未被使用的数组元素称为备用链表。
数组的第一个元素,即下标为0的数组元素的cur存放备用链表的第一个节点的下标;数组的最后一个元素的cur存放第一个有数值的元素的下标。下一位置数据为空的数组元素,其cur为0。
1)插入
首先返回头元素的cur,即第一个空闲元素的下标,假设为p;另外还要给头元素的cur赋一个新值(即元素p的cur,下一个空闲元素的下标)
要在乙和丁之间插入丙,假设乙下标为m,丁下标为m+1。
形象的解释:先告诉乙,让其cur改为p;然后告诉丙,你只需要把你的cur改为m+1,问题就解决了。
2)删除
让数组最后元素的cur改为被删除元素的cur;
让被删除元素成为第一个优先空位(即头元素的cur改为被删除元素的下标)。
#include <iostream> using namespace std; //静态链表 #define MAXSIZE 1000 #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define MAXSIZE 20 typedef int elemtype; typedef int status; typedef struct{ elemtype data; int cur; }component,staticlinklist[MAXSIZE]; status initlist(staticlinklist space){ int i; for(i=0;i<MAXSIZE-1;i++){ space[i].cur=i+1; } space[MAXSIZE-1].cur=0;//最后一个元素的cur为0 return OK; } //链表长度 int llength(staticlinklist space){ int j=0; int i=space[MAXSIZE].cur; while(i){ i=space[i].cur; j++; } return j; } //备用链表 int malloc_sll(staticlinklist space){ int i=space[0].cur;//第一个备用元素的下标 if (space[0].cur) space[0].cur=space[i].cur;//第一个备用元素被使用后,需更新头元素的cur return i; } //插入 status linsert(staticlinklist L,int i,elemtype e){ int j,k,l; k=MAXSIZE-1;//最后一个元素的下标 if(i<1||i>MAXSIZE+1) return ERROR; j=malloc_sll(L); if (j) { L[j].data=e; for(l=1;l<i;l++){ k=L[k].cur;//返回第i-1个元素的下标 } L[j].cur=L[k].cur; L[k].cur=j;//即第i个元素的下标为j,或者说第i-1个元素的cur指向j return OK; } return ERROR; } void free_sll(staticlinklist space,int k){ space[k].cur=space[0].cur;//将头元素的cur赋给要删除元素的cur。 //即要删除元素称为备用链表的最优先元素,原来的最优先元素被降级为要删除元素的下一空闲元素 space[0].cur=k; } //删除 status ldelete(staticlinklist L,int i){ int j,k; k=MAXSIZE-1; if(i<1||i>llength(L)+1) return ERROR; for (j=1;j<i;j++){ k=L[k].cur; } j=L[k].cur; L[k].cur=L[j].cur; free_sll(L,j); return OK; }
线性表