链表的实现(带头结点)
按照数据结构与算法分析:C语言描述(第二版)(黑皮书)实现。
单链表(指针实现)
类型声明
struct ElementType;
struct Node;
typedef struct Node *Ptr2Node;
typedef Ptr2Node List;
typedef Ptr2Node Position;
struct ElementType
{
int id;//id是唯一标识
char name[20];
};
struct Node{
ElementType element;
Position next;
};
初始化
算法流程:创建头节点并分配空间
找特定元素所在位置
算法流程:从首结点开始遍历链表直到找到元素X的位置
找特定元素结点的前驱所在位置
算法流程:从头节点开始遍历链表,直到P->next->element==X
删除
算法流程:找待删结点前驱,创建一个中间指针用于删除X指针
void Delete(ElementType X,List &L){
Position P,tmpCell;
P=FindPrevious(X,L);
if(!IsLast(P,L)){
/*X被找到了*/
tmpCell=P->next;
P->next=tmpCell->next;
tmpCell=NULL;
free(tmpCell);
}
}
插入(P位置的下一个位置)
算法流程:新建结点T并分配空间,T->next改为P->next,P->next改为T,(注意顺序)T->element写入X。
//未用到L,插入P位置的下一个位置(即P指向的位置)
void Insert(ElementType X,List &L,Position P){
Position tmpCell;
tmpCell=(Position)malloc(sizeof(Node));
if(tmpCell==NULL){
printf("out of space\n");
exit(0);
}
tmpCell->element=X;
tmpCell->next=P->next;
P->next=tmpCell;
}
完整代码
#include<stdio.h>
#include<stdlib.h>
struct ElementType;
struct Node;
typedef struct Node *Ptr2Node;
typedef Ptr2Node List;
typedef Ptr2Node Position;
int InitList_v1(List &L);
int InitList_v2(List *L);
List MakeEmpty(List L);
int IsEmpty(List L);
int IsLast(Position P,List L);
Position Find(ElementType X,List L);//找X元素结点的位置P
void Delete(ElementType X,List &L);
Position FindPrevious(ElementType X,List L);
void Insert(ElementType X,List &L,Position P);
void DeleteList(List L);
Position Header(List L);//找头节点位置
Position First(List L);//找链表首结点
ElementType Retrieve(Position P);//取P位置的元素值
void PrintList(List L);
void PrintElement(ElementType e);
struct ElementType
{
int id;//id是唯一标识
char name[20];
};
struct Node{
ElementType element;
Position next;
};
/*
利用函数引用,L是头节点
*/
int InitList_v1(List &L){
L=(Ptr2Node)malloc(sizeof(Node));//头节点分配空间
if(L==NULL) return 0;
L->next=NULL; return 1;
}
/*利用指针传地址*/
int InitList_v2(List* L){
*L=(Ptr2Node)malloc(sizeof(Node));
if(L==NULL) {
printf("out of space\n");
return 0;
}
(*L)->next=NULL; return 1;
}
//L为空链表时返回true
int IsEmpty(List L){
return L->next==NULL;
}
//当前位置是否是链表末尾
int IsLast(Position P,List L){
return P->next==NULL;
}
//返回某个元素X在表中位置,未找到时返回空指针
Position Find(ElementType X,List L){
Position P;
P=L->next;
while (P!=NULL && P->element.id != X.id)
{
P=P->next;
}
return P;
}
//返回某个元素X在表中的前驱的位置,未找到时返回到链表的最后位置
Position FindPrevious(ElementType X,List L){
Position P;
P=L;//若第一个结点是待查结点,其前驱是头节点(或理解为无前驱)
while(P->next!=NULL &&P->next->element.id!=X.id)
{
P=P->next;
}
return P;
}
//删除链表中某个元素X
void Delete(ElementType X,List &L){
Position P,tmpCell;
P=FindPrevious(X,L);
if(!IsLast(P,L)){
/*X被找到了*/
tmpCell=P->next;
P->next=tmpCell->next;
tmpCell=NULL;
free(tmpCell);
}
}
//未用到L,插入P位置的下一个位置(即P指向的位置)
void Insert(ElementType X,List &L,Position P){
Position tmpCell;
tmpCell=(Position)malloc(sizeof(Node));
if(tmpCell==NULL){
printf("out of space\n");
exit(0);
}
tmpCell->element=X;
tmpCell->next=P->next;
P->next=tmpCell;
}
Position Header(List L)
{
return L;
}
Position First(List L)
{
return L->next;
}
ElementType Retrieve(Position P)
{
return P->element;
}
void PrintElement(ElementType e)
{
printf("id:%d---name:%s\n",e.id,e.name);
}
void PrintList(List L)
{
printf("LinkList--------------\n");
printf("location-----next(if exist)------data_id-----data_name\n");
Ptr2Node P=L->next;//首结点的位置
while (P!=NULL)
{
if(P->next!=NULL){
printf("0x%x-----0x%x-----%d-----%s\n",P,P->next,
P->element.id,P->element.name);
}else{
printf("0x%x-----%d-----%s\n",P,
P->element.id,P->element.name);
}
P=P->next;
}
}
int main(){
List L;
InitList_v2(&L);
printf("%d\n",IsEmpty(L));
printf("%d\n",IsLast(L,L));
ElementType e_1={1,"zhangsan"};
ElementType e_2={2,"lisi"};
ElementType e_3={3,"Alice"};
ElementType e_4={4,"Bob"};
/*
1插到头节点后
2插到1后
3插到头结点后
*/
Insert(e_1,L,Header(L));
//Position ptr=Find(e_1,L);
Insert(e_2,L,Find(e_1,L));
Insert(e_3,L,Header(L));
PrintList(L);
Delete(e_3,L);
PrintList(L);
PrintElement(Retrieve( First(L)));
getchar();
}
静态链表(链表的游标实现)(数组模拟链表)
使用该方法,0号空间和最后一个数组空间被占用,不能存数据
0号空间存放freelist首元素的地址(数组下标)
最后一个数组空间指向链表首元素
freelist是指数组空间中未被利用的部分,这些部分通过cur连成了一个空闲链表
初始化方式应该是:0号空间指向freelist首元素(即1号空间),最后一个空间指向链表首元素(初始化时表内无元素,置为0(视为nullptr))。
重点:倒数第二个空间的cur置为0,因为倒数第二个空间是最后一个可以分配的空间,应该不指向下一个元素了。
类型定义
#define MAXSIZE 5
typedef struct {
char name[20];
int score;
}Element;
typedef struct {
Element data;
int cur; //游标,为0时表示无指向
}Component,StaticLinkList[MAXSIZE];
/*
这个写法等价于
typedef struct {
Element data;
int cur; //游标,为0时表示无指向
}Component;
typedef Component StaticLinkList[MAXSIZE];
*********typedef int data[max]; data a; a就是一个int[max]
即为Component类型创建一个数组类型,叫 StaticLinkList
*/
/*
完整代码
#include<stdio.h>
//静态链表最大长度 ,能存放数据的位置是maxsize-2,一个位置放空闲结点位置,一个位置当头节点
#define MAXSIZE 5
typedef struct {
char name[20];
int score;
}Element;
typedef struct {
Element data;
int cur; //游标,为0时表示无指向
}Component,StaticLinkList[MAXSIZE];
/*
这个写法等价于
typedef struct {
Element data;
int cur; //游标,为0时表示无指向
}Component;
typedef Component StaticLinkList[MAXSIZE];
*********typedef int data[max]; data a; a就是一个int[max]
即为Component类型创建一个数组类型,叫 StaticLinkList
*/
/*
结构体数组
静态链表第一个元素和最后一个元素特殊处理
第一个元素cur存备用链表第一个结点的下标
最后一个元素cur存第一个有数值的元素的下标(头结点)
*/
//初始化静态链表
int InitLinkList(StaticLinkList space){
for(int i=0;i<MAXSIZE-2;i++){
space[i].cur=i+1;
}
space[MAXSIZE-2].cur=0;
space[MAXSIZE-1].cur=0;//当前链表为空
return 1;
}
void PrintElement(Element e){
printf("element--%d--%s \n",e.score,e.name);
}
void PrintSpace(StaticLinkList space){
printf("=====================\n");
for(int i=0;i<MAXSIZE;i++){
if(space[i].data.score==NULL){
printf("Pos--%d Next--%d\n",i,space[i].cur);
}
else{
printf("Pos--%d Next--%d ",i,space[i].cur);
PrintElement(space[i].data);
}
}
}
/*
第一个元素的cur指向备用链表第一个结点下标
最后一个有值元素的cur设为0(指向第一个结点,然后第一个结点会指向备用链表的头)
*/
//分配空闲链表,即返回空闲链表的第一个下标 ,若空闲链表空返回0
int Malloc_SSL(StaticLinkList space){
int i=space[0].cur; //指向备用链表的第一个结点的下标
if(space[0].cur){
if(space[i].cur!=MAXSIZE-1)//若i的游标不指向最后一个位置
{
space[0].cur=space[i].cur; //更新第一个结点的cur
}
else{
printf("这是可分配的最后一个结点\n");
space[0].cur=0; // 设置第一个结点的cur为0,表示无空闲数组
}
}
if(i==0)
printf("无空闲结点\n");
return i; //i是空闲链表的1第一个下标
}
//表长
int Length_SSL(StaticLinkList space){
int cnt=0;
int node_i=space[MAXSIZE-1].cur;
//最后一个有值元素的cur为0,cnt前n-1个元素
while(node_i!=0){
cnt++;
node_i=space[node_i].cur;
}
return cnt;
}
//插入 插到第i个位置,即原链表第i个元素的前面
int Insert_SSL(StaticLinkList space,int i,Element e){
//1 -> length+1 length+1个插入位置
if(i<1||i>Length_SSL(space)+1){
printf("insert position unreasonable\n");
return 0;
}
int free_location=Malloc_SSL(space);//分配结点位置
//判断是否有空闲
if(free_location==0){
printf("freelist is full\n");
return 0;
}
space[free_location].data=e;
//找原来的第i-1个元素,即k
int k=MAXSIZE-1;
for(int j=0;j<i-1;j++){
k=space[k].cur;
}
space[free_location].cur=space[k].cur;
space[k].cur=free_location;
return 1;
}
//回收下标为k的结点(撤销分配的元素)
int Free_SSL(StaticLinkList space,int k){
//k不能是第一个和最后一个结点
if(k<1||k>=MAXSIZE-1){
printf("回收位置不合理");
return 0;
}
space[k].data.score=NULL;
space[k].cur=space[0].cur;//k的cur指向原来的优先空位
space[0].cur=k; //使k位置成为优先空位
return 1;
}
//删除第i个元素
int Delete_SSL(StaticLinkList space,int i){
if(i<1||i>Length_SSL(space)){
printf("删除位置不合理");
return 0;
}
int k=MAXSIZE-1; //最后一个结点
int j;
//找第i-1个元素
for(j=1;j<=i-1;j++){
k=space[k].cur;
}
//如果第i-1个元素是第0个元素?若删除掉了最后一个元素,游标得置为0
j=space[k].cur;//j位置是第i个元素
space[k].cur=space[j].cur;//第i-1个元素的游标改为第i+1个元素的位置
Free_SSL(space,j);//释放第i个元素所在位置
return 1;
}
int main(){
StaticLinkList space;
InitLinkList(space);
Element e_1={"zhang1",1};
Element e_2={"zhang1",2};
Element e_3={"zhang1",3};
Element e_4={"zhang1",4};
Element e_5={"zhang1",5};
Insert_SSL(space,1,e_1);
Insert_SSL(space,2,e_2);
PrintSpace(space);
Insert_SSL(space,3,e_3);
Insert_SSL(space,4,e_4);
PrintSpace(space);
Insert_SSL(space,1,e_5);
PrintSpace(space);
printf("\n cnt=%d",Length_SSL(space));
Delete_SSL(space,0);
Delete_SSL(space,4);
Delete_SSL(space,2);
PrintSpace(space);
printf("\n cnt=%d",Length_SSL(space));
//Insert_SSL(space,3,e_2);
Insert_SSL(space,2,e_2);
PrintSpace(space);
printf("\n cnt=%d",Length_SSL(space));
Delete_SSL(space,1);
Delete_SSL(space,1);
PrintSpace(space);
Delete_SSL(space,1);
PrintSpace(space);
// printf("\n cnt=%d",Length_SSL(space));
// Insert_SSL(space,1,e_1);
//
// printf("\n cnt=%d",Length_SSL(space));
// Insert_SSL(space,2,e_2);
// PrintSpace(space);
//
//
// printf("\n cnt=%d",Length_SSL(space));
// Insert_SSL(space,3,e_3);
// printf("\n cnt=%d",Length_SSL(space));
// Insert_SSL(space,1,e_5);//出错
// PrintSpace(space);
// printf("\n cnt=%d",Length_SSL(space));
printf("\n cnt=%d",Length_SSL(space));
Insert_SSL(space,3,e_1);
printf("\n cnt=%d",Length_SSL(space));
Insert_SSL(space,2,e_2);
PrintSpace(space);
printf("\n cnt=%d",Length_SSL(space));
Insert_SSL(space,2,e_3);
printf("\n cnt=%d",Length_SSL(space));
Insert_SSL(space,1,e_5);//出错
PrintSpace(space);
printf("\n cnt=%d",Length_SSL(space));
return 0;
}