不带头结点的单链表
定义
线性表的链式存储又称单链表,它是指通过一组任意的存储单元来存储线性表中的数据元素。为了建立元素间的线性关系,每个节点除了存放自身的信息外,还要存放一个指向下一个结点的指针。其结构图如下
| data| next|
结点类型定义代码如下
typedef struct{ //定义单链表结点类型
ElemType data; //数据域
struct LNode *next; //指针域
}LNode,*LinkList;
//LNode:struct类型的别名,LNode*LinkList:指向链表的指针,相当于struct LNode *LinkList;
初始化
void InitList(LinkList *L){
// 创建链表时要将改变值传回main函数,所以用引用类型的参数
*L = NULL;
}
调用InitList(&head);
方式二:
void InitList(LNode *head){
head=NULL;
}
判断是否是空表
bool Empty(LinkList L) //判断链表是否为空
{
return (L==NULL);
}
求表长
int GetLength(LinkList L)
{
int len = 0;
if(L == NULL){
printf("空表");
return len;
}
LNode *p= &L;
while(p != NULL){
p = p->next;
len++;
}
return len;
}
打印表
void PrintList(LinkList L)
{
if(L==NULL) return;
LNode *p = L;
while(p){
printf("%d-->",p->data);
p = p->next;
}
printf("NULL\n");
}
查找
按位查找结点
LNode *GetElem(LinkList L,int i){
if(i == 1) return L;
if(i < 1) return NULL;
int j = 0;
LNode *p = L;
while(p != NULL&& j<i){
p = p->next;
j++;
}
return p;
}
按值查找结点
LNode *GetElem(LinkList L,int e){
LNode *p = L;
while(p && p->data != e)
p =p->next;
return p;
}
插入
指定结点的后插操作
//指定结点的后插操作
bool InsertNextNode(LNode *p,int e){
if(p == NULL){
return false;
}
LNode *s = malloc(sizeof(LNode));
if(s == NULL) {
return false; //分配空间失败
}
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
在给定结点前插入
将要插入的节点的数据与指定结点的数据交换,然后将这个新节点接在给定结点后
bool InsertPrioNode(LNode *p,int e){
if(p==NULL){
return false;
}
LNode *s = malloc(sizeof(LNode));
s->data = p->data;
p->data = e;
s->next = p->next;
p->next = s;
return true;
}
按位序插入
bool ListInsert(LinkList *L,int i,int e){
//*L表示指向第一个结点的 L的指针
if(i<1){
return false;
}
if(i == 1)
{
LNode *s = malloc(sizeof(LNode));
s->data = e;
s->next = *L;
*L = s;
return true;
}
LNode *p = GetElem(*L,i - 1); //获取前一个结点
InsertNextNode(p,e);
return true;
}
创表
头插法
void CreateListH(LinkList *L){
LNode *t;
int a,n,i=0;
printf("请输入表长:");
scanf("%d",&n);
while(i < a){
scanf("%d",&a);
t=(LNode *)malloc(sizeof(LNode));
t->data=a;
t->next=*L;
*L = t;
i++;
}
}
尾插法
void CreatListT(LinkList *L){
LNode *p,*t; /*p工作指针,t临时指针*/
int a,i=1;
while(scanf("%d",&a)){
if(a!=0){
t=(LNode *)malloc(sizeof(LNode));
t->data=a;
if(i==1){
*L=t;
}
else{
p->next=t;
}
p=t;
}
else{
p->next=NULL;
break;
}
i++;
}
}
删除
删除给定结点
bool DeleteList(LNode *p){
if(p==NULL) return false;
LNode *q = p->next;
p->data = q->data;
p->next = q->next;
free(q);
return true;
}
按序位删除
bool DeleteList(LinkList *L,int i,int *e){
LNode *p = GetElem(*L,i);
DeleteList(p);
return true;
}
销毁表
void DestoryLinklist(LinkList *L){
//摧毁链表
LinkList cur = *L;
LinkList pre = NULL;
if (*L == NULL){
printf("链表为空");
return ;
}
if (cur->next = NULL){
*L = NULL;
free(cur);
cur = NULL;
return ;
}
while(cur){
pre = cur;
cur = cur->next;
free(pre);
pre = NULL;
}
}
总结:不带头结点的遍历,增加结点等操作的循环判断条件都是 L != NULL,增删结点,创建链表,初始化等操作都需要用到函数值传递,所以函数的参数都用指针