带头结点的单链表
定义
typedef struct{ //定义单链表结点类型
ElemType data; //数据域
struct LNode *next; //指针域
}LNode,*LinkList;
//LNode:struct类型的别名,LNode*LinkList:指向链表的指针,相当于struct LNode *LinkList;
初始化
bool InitList(LinkList *L) {
*L = (LinkList)malloc(sizeof(LNode));
if(*L==NULL) {
printf("初始化失败,分配内存失败 ");
return false; //分配内存失败
}
(*L)->next = NULL;
}
判断是否是空表
bool Empty(LinkList L) {
if(L->next == NULL) return true;
return false;
}
求表长
int Leng(LinkList L) {
if( L->next==NULL ) {
printf("空表");
return 0;
}
int i = 0;
LNode *p = L->next;
while(p) {
p = p->next;
i++;
}
return i;
}
打印表
void Print(LinkList L) {
printf("这个链表为:");
LNode *p = L->next;
if(p==NULL) {
printf("空表");
return ;
}
while(p != NULL) {
printf("%d-->",p->data);
p = p->next;
}
printf("NULL\n");
}
查找
按位查找结点
LNode *GetElem(LinkList L,int i) {
if(i == 0) return L;
if(i < 1) return NULL;
LNode *p = L->next;
int j = 1;
while(p &&j < i-1) {
p = p->next;
j++;
}
return p;
}
按值查找结点
LNode *GetElem(LinkList L,int e){
LNode *p = L->next;
while(p && p->data != e)
p =p->next;
return p;
}
插入
指定结点的后插操作
//指定结点的后插操作
bool InsertNext(LNode *p,int e) {
if(p == NULL) return false; //错误的指针
LNode *q =malloc(sizeof(LNode));
if(q==NULL) {
printf("申请空间失败");
return false;
}
q->data = e;
q->next = p->next;
p->next = q;
return true;
}
在给定结点前插入
将要插入的节点的数据与指定结点的数据交换,然后将这个新节点接在给定结点后
bool InsertPre(LNode *p,int e){
if(p==NULL) return false; //错误的指针
LNode *q =malloc(sizeof(LNode));
p->data = q->data;
p->data = e; //转化为后插操作
q->next = p->next; //将给定结点的数据域与新节点交换
p->next = q->next; //然后将新节点连入给定结点的后面
return true;
}
按位序插入
//按位插入
bool InsertOrder(LinkList *L,int i,int e) {
if(i < 1) return false;
LNode *q = malloc(sizeof(LNode)) ;
LNode *p = GetElem(*L,i-1); //获取第 i-1 个结点
q->data = e;
q->next = p->next;
p->next = q;
return true;
}
创表
头插法
void CreateList_head(LinkList *L) {
printf("请输入你想要创建的单链表的长度:");
InitList(L);
int n,a,i = 0;
scanf("%d",&n);
while( i<n ) {
scanf("%d",&a);
LNode *p = malloc(sizeof(LNode));
p->data = a;
p->next = (*L)->next;
(*L)->next = p;
p = p->next;
i++;
}
}
尾插法
//尾插法
void List_TailInsert(LinkList *L) {
printf("请输入你想要创建的单链表的长度:");
InitList(L);
LNode *p,*tail = (*L);
int n,a,i = 0;
scanf("%d",&n);
while( i<n ) {
scanf("%d",&a);
p = malloc(sizeof(LNode));
p->data = a;
tail->next = p;
tail = p; //不断指向尾节点
i++;
}
tail->next = NULL;
}
删除
删除给定结点
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){
//摧毁链表
LNode cur = (*L)->next;
LNode pre = NULL;
if (cur == NULL){
printf("链表为空");
return ;
}
if (cur->next = NULL){ //cur为尾指针
cur = NULL;
free(cur);
return ;
}
while(cur){
pre = cur;
cur = cur->next;
free(pre);
pre = NULL;
}
}
总结:不带头结点的遍历,增加结点等操作的循环判断条件都是 L != NULL,带头结点的循环判断条件都是 L->next != NULL,增删结点,创建链表,初始化等操作都需要用到函数值传递,所以函数的参数都用指针