顺序表和链表的比较:
1、基于空间的比较
1)存储分配的方式:顺序表的存储空间是一次性分配的,链表的存储卡空间是多次分配的。
2)存储密度(存储密度=结点域值所占的存储量/结点结构所占的存储总量):
顺序表的存储密度=1,链表的存储密度<1(因为结点中有指针域)
2、基于时间的比较
1)存取方式:
顺序表可以随机存取,链表只能顺序存取
2)插入/删除时移动元素的个数:
顺序表平均需要移动近一半元素;链表不需要移动元素,只需要修改指针。
一、结构体定义
//顺序表的结构体定义
#define maxSize 100
typedef struct
{
int data[maxSize];
int length;
}Sqlist;
//或如下常用定义
int A[maxSize];
int n; //n表示顺序表的长度
//单链表结点定义
typedef structure LNode
{
int data; //data中存放结点数据域
struct LNode *next; //指向后继结点的指针
}LNode; //定义单链表结点
//双链表结点定义
typedef struct DLNode
{
int data;
struct DLNode *prior;
struct DLNode *next;
}DLNode; //定义双链表的结点类型
LNode *A=(LNode *)malloc(sizeof(LNode));
//这里的A命名了两个东西:一个是结点,另一个是指向这个结点的指针;
二、顺序表的初始化、查找、插入及删除操作
//初始化顺序表
void initList(Sqlist &L) //L本身要改变所以用引用型
{
L.length=0;
}
//在顺序表中查找一个元素等于e的值
int findElem(Sqlist L,int e)
{
int i;
for(i=0;i<L.length;++i)
if(e==L.data[i])
return i; //若找到返回下标
return -1; //若没找到,返回-1
}
//插入数据元素
int insertElem(Sqlist &L,int p,int e) //L本身要发生变化,所以用引用型
{
int i;
if(p<0||p>L.length||L.length==maxSize) //位置错误或者表长已经达到
return 0; //顺序表的最大允许值,此时插入不成功,返回0
for(i=L.lenth-1;i>=p;--i)
L.data[i+1]=L.data[i]; //从后往前,逐个讲元素往后移动一个位置
L.data[p]=e; //将e放在插入位置p上
++(L.lenth); //表内元素多了一个,因此表长自增1
return 1; //插入成功,返回1
}
//删除操作
int deleteElem(Sqlist &L,int p,int &e) //要改变的变量用引用型
{
int i;
if(p<0||p>L.length-1)
return 0; //位置不对返回0,代表删除不成功
e=L.data[p]; //将被删除元素赋给e
for(i=p;i<L.lenth-1;++i) //从p位置开始,将后边的元素逐次前移一个位置
L.data[i]=L.data[i+1];
--(L.length); //表长减1
return 1; //删除成功,返回1
}
//用e返回L中p位置上的元素
int getElem(Sqlist L,int p,int &e) //要改变所以用引用型
{
if(p<0||p>L.length-1)
return 0;
e=L.data[p];
return i;
}
三、单链表的创建、归并、查找、删除操作。
单链表的的创建包括头插法和尾插法两种。
//尾插法建立链表C
void createListR(LNode *&C,int a[],int n) //要改变的变量用引用型
{
LNode *s ,*r; //s用来指向新申请的结点,r始终指向C的终端结点
int i;
C=(LNode *)malloc(sizeof(LNode)); //申请C的头结点空间
C->next=NULL;
r=C; //r指向头结点,因为此时头结点就是终端结点
for(i=0;i<n;++i) //循环申请n个结点来接受数组a中的元素
{
s=(LNode *)malloc(sizeof(LNode)); //s指向新申请的结点
s->data=a[i]; //用新申请的结点来接受a中的一个元素
r->next=s; //用r来接纳新结点
r=r->next; //r指向终端结点,以便接纳下一个到来的结点
}
r->next=NULL; //数组a中的所以元素都已经转入链表C中,
//C的终端结点的指针域置为NULL
}
//头插法建立链表C
void createListF(LNode *&C,int a[],int n)
{
LNode *s;
int i;
C=(LNode *)malloc(sizeof(LNode));
C->next=NULL;
for(i=0;i<n;++i)
{
s=(LNode *)malloc(sizeof(LNode));
s->data=a[i];
s->next=C->next; //s所指新结点的指针域next指向C中的开始结点
C->next=s; //头指针的指针域指向s结点,使得s成为新的开始结点
}
}
//A和B是两个带表头结点的单链表,其元素均递增有序,
//将A和B归并成一个元素非递减的链表C(采用尾插法)
void merge(LNode *A,LNode *B,LNode *C)
{
LNode *p=A->next; //p来追踪A的最小结点
LNode *q=B->next; //q来追踪B的最小结点
LNode *r; //r始终指向C的终端结点
C=A; //用A的头结点来做C的头结点
C->next=NULL;
free(B); //B的头结点已无用释放掉
r=C; //r指向C,因为此时头结点也是终端结点
while(p!=NULL && q!=NULL)
//当p与q都不空时,选取p与q所指结点中的较小者插入C的尾部
{ /*下面的语句中,r始终指向当前链表的终端结点,作为接纳新
结点的一个媒介通过它新结点被链接入C并且重新指向新的终端
结点,以便接受下一个新结点*/
if(p->data<=q->data)
{
r->next=p;p=p->next;
r=r->next;
}
else
{
r->next=q;q=q->next;
r=r->next;
}
}
r->next=NULL;
/* 将还有剩余结点的链表链接在C的尾部 */
if(p!=NULL) r->next=p;
if(q!=NULL) r->next=q;
}
//采用头插法归并成递减的单链表算法
void merge(LNode *A,LNode *B,LNode *C)
{
LNode *p=A->next;
LNode *q=B->next;
LNode *s;
C=A;
C->next=NULL;
free(B);
while(p!=NULL && q!=NULL)
{ //下面的if else 语句体现了链表的头插法
if(p->data<=q->data)
{
s=p;p=p->next;
s->next=C->next;
C->next=s;
}
else
{
s=q;q=q->next;
s->next=C->next;
C->next=s;
}
}
/* 必须将剩余元素逐个插入C的头部才能得到最终的递减序列 */
while(p!=NULL)
{
s=p;
p=p->next;
s->next=C->next;
C->next=s;
}
while(q!=NULL)
{
s=q;
q=q->next;
s->next=C->next;
C->next=s;
}
}
//查找并删除带头结点单链表中掉的一个值为x的结点
int findAndDelete(LNode *C,int x)
{
LNode *p,*q;
p=C;
/*查找部分开始*/
while(p->next!=NULL)
{
if(p->next->data=x)
break;
p=p->next;
}
/* 查找部分结束*/
if(p->next=NULL)
return 0;
else
{
/*删除部分开始*/
q=p->next;
p->next=p->next->next;
free(q);
/*删除部分结束*/
reuturn 1;
}
}
四、双链表建立、查找、插入、删除操作
//采用尾插法建立双链表
void createDlistR(DLNode *&L,int a[],int n)
{
DLNode *s,*r;
int i;
L=(DLNode *)malloc(sizeof(DLNode));
L->prior=NULL;
L->next=NULL;
r=L; //r始终指向终端结点
for(i=0;i<n;++i)
{
s=(DLNode *)malloc(sizeof(DLNode)); //创建新结点
s->data=a[i];
/* 将s插入到L的尾部,并且r指向s,s->priror=r; */
r->next=s;
s->prior=r;
r=s;
}
r->next=NULL;
}
//查找结点算法
DLNode* findNode(DLNode *C,int x)
{
DLNode *p=C->next;
while(p!=NULL)
{
if(p->data==x)
break;
p=p->next;
}
return p; //若找到,则p中内容是结点地址循环因break结束,
//若未找到则p中内容是NULL
}
//插入结点操作
s->next=p->next;
s->prior=p;
p->next=s;
s->next->prior=s;
//删除结点操作
q=p->next;
p->next=q->next;
q->next->prior=p;
free(q);