c/c++伪代码形式:
//单链表基本操作
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status
typedef char ElemType
//单链表
typedef struct Lnode{
ElemType data;
struct Lnode*next;
}LNode,*LinkList;
//单链表重要操作
p = L;//p指向头结点
s = L->next;//s指向首元结点
p = p->next;//p指向下一结点
//初始化
Status InitList_L(LinkList L){
L = (LinkList)malloc(sizeof(LNode));//L是头指针是头结点的地址
L->next = NULL;//下面没有结点(无首元结点)
return OK;
}
//取值:取单链表中第i个元素的内容
/*1、从第一个结点(L->next)顺链扫描,用指针p指向当前扫描到的结点,p处置p=L->next
2、j做计数器,累计当前扫描过的结点数,j初值为1
3、当p指向扫描到的下一结点时,计数器j加1
4、当j==i时,p所指的结点就是要找的第i个结点*/
Status GetElem_L(LinkList L, int i,ElemType &e){//获取线性表L中的某给数据元素的内容,通过e(引用)返回
p = L->next;//初始化从首元元素触发
j = 1;//计数器
while(p&&j<i){//向后扫描,直到p指向第i个元素或p为空
p = p->next;
++j;
}
if(!p||j>i)return ERROR;//第i个元素不存在
e = p->data;
return OK;
}
//查找:按值查找:根据指定数据获取该数据所在的位置(该数据的地址
//按值查找:根据指定数据获取该数据所在的位置序号(时第几个数据元素)
/*1、从第一个结点起,依次和e相比较
2、如果找到一个其值与e相等的数据元素,则返回其在链表中的“位置”或地址
3、如果查遍整个链表都没有找到其值和e相等的元素,则返回0或“NULL”*/
LNode *LocateELem_L(LinkList L,Elemtype e){
//找到,则返回L中值为e的数据元素的地址,查找失败返回NULL
p = L->next;
while(p&&p->data!=e)
p = p ->next;
return p;
}
int LocateElem_L(LinkList L,Elemtype e){
//返回L中值为e的数据元素的位置序号,查找失败返回0
p = L->next;
j = 1;
while(p&&p->data!=e){
p = p->next;
j++;
}
if(p) return j;
else return 0;
}
//插入:在第i个结点前插入值为e的新结点
/*1、首先找到ai-1的存储位置p
2、生成一个数据域为e的新结点s
3、插入新结点:(1)新结点的指针域指向结点ai
(2)结点ai-1的指针域指向新结点*/
//在L中第i个元素之前插入数据元素e
Status Listlnsert_L(LinkList *L,int i,ElemType e){
p = L;//从头结点出发
j = 0;//计数器
while ((p&&j<i-1)){//寻找第i-1个结点,p指向i-1结点
p = p->next;
++j;
}
if(!p||j>i-1)return ERROR;//i大于表长+1或者小于1,插入位置非法
s = (LinkList)malloc(sizeof(LNode));//生成新节点s,将结点s的数据域置为e
s->data =e;
s -> next = p -> next
p -> next = s;
return OK;
}
//删除:删除第i个结点
/*1、先找到ai-1的存储位置p,保存要删除的ai的值
2、令p->next指向ai+1
3、释放结点ai的空间*/
Status ListDelete_L(LinkList*L,int i,ElemType &e){
p = L;
j = 0;
while(p->next&&j<i-1){
p = p->next;
++j;//寻找第i个结点,并令p指向其前驱
}
if(!(p->next)||j>i-1)return ERROR;//删除位置不合理
q = p->next //临时保存被删结点的地址以备释放
p ->next = q ->next;//改变删除结点前驱结点的指针域p ->next = p ->next -》next
e = q->data//保存删除结点的数据域
free(q);//释放删除结点的空间
return OK;
}
//销毁链表
Status DestroyList_L(LinkList L){
LNode *p//或LinkList p;
while(L){
p = L;//清除p,L去找下一个,如果直接清除L就找不到下一个了
L = L->next;
free(p);
}
}
//清空链表(销毁是毁坏整个链表,清空会保留链表(L存在)但元素为0
Status clearlist(LinkList L){//将L重置为空表
LNode *p,*q;//或Linklist p,q
p = L->next;
while(p){//没到表尾
q = p->next;//p,q两个哨兵,q去找p的下一个
free(p);
p = q
}
L ->next = NULL;//头结点指针域为空
return OK;
}
//求单链表表长
int ListLength_L(LinkList L){
LNode *p;
p = L->next//p指向首元结点
int i = 0;
while(p){
i++;
p = p->next;
}
return i;
}
//建立单链表:
//头插法——元素插入在链表头部,也叫前插法
/*1、从一个空表开始,重复读入数据;
2、生成新结点,将读入数据存放到新结点的数据域中
3、从最后一个结点开始,依次将各结点插入到链表的前端*/
void CreateList_H(LinkList L,int n){
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;//创建头结点
for(i = n;i > 0;--i){
p = (LinkList)malloc(sizeof(LNode));//建立第一个结点
scanf("%d",&p->data);//插入结点
p ->next = L ->next;//新结点指向头结点之后的结点
L ->next = p;
}
}
//尾插法——元素插入在链表尾部,也叫后插法
/*1、从一个空表L开始,将新结点逐个插入到链表的尾部,尾
指针R指向链表的尾结点
2、初始时,R同L均指向头结点,每读入一个数据元素则申请一个新结点,
将新结点插入到尾结点后,R指向新结点*/
void CreateList_R(LinkList *L,int n){
L = (LinkList)malloc(sizeof(LNode));
LinkList *R = L;
for(int i = 0;i < n;i++){
p = (LinkList)malloc(sizeof(LNode));
p ->next = NULL;
R ->next = p;
R = p;
}
}
//双向链表
typedef struct DuLNode{
Elemtype data;
struct DuLNode *prior,*next;
}DuLNode,*DuLinkList;
//双向链表的插入
Status Listlnsert_DuL(DuLinkList &L,int i, ElemType e){
if(!(p = GetElemP_DuL(L,i)))return ERROR;
s = (DuLNode*)malloc(sizeof(DuLNode));
s -> data = e;
s -> prior = p -> prior;
p -> prior ->next = s;
s -> next = p;
p -> prior = s;
return OK;
}
//双向链表的删除
void ListDelete_DuL(DuLink &L,int i,ElemType &e){
//删除带头结点的双向循环链表L的第i个元素,并用e返回
if(!(p= GetElemP_DuL(L,i)))return ERROR;
e = p->data;//保存被删元素
p -> prior -> next = p -> next;
p -> next -> prior = p -> prior;
free(p);
return OK;
}
顺序表和链表的比较:
顺序表 | 链表 | ||
空间 | 存储空间 | 预先分配,会导致空间闲置或溢出 | 动态分配,不会出现空间闲置或溢出 |
存储密度 | 不用为表示结点间的逻辑关系而增加额外的存储开销,存储密度等于1 | 需要借助指针来体现元素间的逻辑关系,存储密度小于1 | |
时间 | 存取元素 | 随机存取,按位置访问元素的时间复杂度为O(1) | 顺序存取,按位置访问元素时间复杂度为O(n) |
插入、删除 | 平均移动约表中一半元素,时间复杂度为O(n) | 不需移动元素,确定插入、删除位置后、时间复杂度为O(1) | |
适用情况 | 1、表长变化不大,且能事先确定变化的范围 2、很少进行插入或删除操作、经常按照元素位置序号访问数据元素 | 1、长度变化较大 2、频繁进行插入或删除操作 |