带头节点的单链表实现
#include <stdio.h>
#include <stdlib.h>//包含动态分配内存空间函数 malloc()和释放空间函数free()
#include <stdio.h>
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
LNode* List_Tail(LNode *L){//尾插法建立单链表
L=(LNode*)malloc(sizeof(LNode));
//此处为了使尾插法得时间复杂度降到O(n)级别,除头节点外额外设置了一个尾指针r (for rear)
LNode *s;
LNode *r=L;//初始的表尾和表头重合 同时rear==L也是队的判空条件 不过这都是后话了
int x;
scanf("%d",&x);
while(x!=9527){
s=(LNode*)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;//表尾元素后继置空
return L;
}
LNode* List_HeadInsert(LNode *L){//头插法建立单链表
LNode *s;
L=(LNode*)malloc(sizeof(LNode));
L->next=NULL;//置空初始操作 因为内存中可能有脏数据影响单链表建立
L->data=5;
int x;
printf("请输入单链表元素");
scanf("%d",&x);
while(x!=9527){
s=(LNode*)malloc(sizeof(LNode));
s->data=x;
s->next=L->next;
L->next=s;
scanf("%d",&x);
}
return L;
}
int length(LinkList L){//度量单链表长度
LNode*p=L->next;//p从第一个数据节点开始
int len=0;
if(L==NULL)return len;
while(p!=NULL){
p=p->next;
len++;
}
return len;
}
int Empty(LinkList L){//本应将返回值定义为_Bool类型的函数,暂将该函数返回值定为int
if(L->next==NULL)return 1;
else return 0;
}
void PrintList(LinkList L){//打印整张表
LNode *p;
p=L->next;
printf("该单链表元素为");
for(int j=0;j<length(L);j++){
if(j==0)printf("单链表内元素分别为%d ",p->data);
else printf("%d ",p->data);
p=p->next;
}
}
LNode *GetElem(LinkList L,int i){
if(i<1||i>length(L))return NULL;
if(i==0)return L;//此处若i 的值为一返回L即表头节点 但在ListDelete()处失效 在失效处还需额外加上i==0的情况
int k=1;
LNode *p=L->next;
while(p&&k<i){
p=p->next;
k++;
}
return p;
}
LNode *LocateElem(LinkList L,int e){
if(!L)return NULL;
LNode *p=L;
while(p){
if(p->data==e)break;
p=p->next;
}
return p;
}
int ListInsert(LinkList L,int i,int e){//指定节点的后插操作 使用之前实现的GetElem()函数来找到第i-1个节点称之为*p节点,插入节点为*s
if(i<1||i>length(L))return 0;//判断i的值是否合法
LNode* p=GetElem(L,i-1);
LNode* s=(LNode*)malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s;
return 1;
}
int forward_ListInsert(LinkList L,int i,int e){//单链表中通常采取后插法,当从表头按位查找到元素的复杂度为O(n)时对第i位的前插可以转化为对i-2位的后插
//此处是王道书上讲的依旧后插但是*p和*s的数据互换
if(i<1||i>length(L))return 0;//判断i的值是否合法
LNode* p=GetElem(L,i-1);
LNode* s=(LNode*)malloc(sizeof(LNode));
s->data=p->data;
s->next=p->next;//此处*s作为后插元素节点数据为 p->data
p->next=s;
p->data=e; //此处*p节点数据值为e
return 1;
}
int ListDelete(LinkList L,int i){//按位删除元素值
if(i<1||i>length(L))return 0;//判定i的值是否合法
LNode *p;
if(i==1)
p=L;
else
p=GetElem(L,i-1);
LNode *q=p->next;
int e=q->data;
p->next=p->next->next;
free(q);
printf("按值删除操作已完成\n\n");
return e;
}
void DestroyList(LinkList L){//依次由头节点删除并释放整张表
L=L->next;
int i=1;
while(L){
LNode*temp=L;
printf("删除单链表中第%d个的元素,值为%d\n",i,temp->data);
L=L->next;
free(temp);
i++;
}
free(L);
}
int main()
{
LNode *temp;
temp=List_HeadInsert(temp);//规定
//temp=List_Tail(L);
PrintList(temp);
printf("\n");
printf("\n");
printf("单链表长度为%d\n",length(temp));
printf("\n");
printf("该链表第三个元素为%d\n",GetElem(temp,3)->data);
printf("\n");
printf("该链表的按值查找元素为%d\n",LocateElem(temp,5)->data);
printf("\n");
if(Empty(temp))printf("这是个空的单链表");else printf("这是个非空的单链表\n");
printf("\n");
//ListInsert(temp,3,1216);//这里是索尔和查克的彩蛋
forward_ListInsert(temp,3,1216);
PrintList(temp);
printf("\n");
printf("\n");
ListDelete(temp,1);
PrintList(temp);
printf("\n");
printf("\n");
DestroyList(temp);
return 0;
}