一、概述
前面我们已经完成了带头结点的链表,今天我们来完成一下不带头结点的链表。事实上不带头结点的链表玉带头结点的链表差别在哪呢?
(1)带头结点的单链表更容易操作,因为不带头结点的单链表在第一个节点的操作与其他节点不一样,在初始化的时候就必须把第一个结点创建出来,然后将它的next置空而不带头结点的单链表则直接置空即可。
(2)不带头结点的单链表,初始化时一定要返回指向头结点的地址,所以要用二级指针。
(3)
不带头结点的单链表在插入、删除、输出时判断条件不一样,不带头结点的单链表判断为空时是while(head!=NULL)而不是while(head->next!=NULL)。
为什么不带头结点初始化有2种方式,而带头结点只有1种方式呢?
因为不带头结点声明Node *head 时;C编译器将其自动初始化为NULL,于是根本不需要调用InitList(head);也即不带头结点的初始化是个伪操作。而带头结点的初始化在堆开辟了一段内存,需要修改head指针变量指向的地址(即head的值),所以要修改head的值,必须传保存head变量的地址(即二维指针)。
二、代码实现
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int Elemtype;
typedef struct Node
{
Elemtype data;
Node* next;
}Node,*plist;
void Initlist(plist *head)
{
(*head) = (plist)malloc(sizeof(Node));
if(NULL == head)exit(0);
(*head)->next = NULL;
}
bool Insert_head(plist head,Elemtype val)
{
bool rt = false;
plist After = head-> next;
plist NewNode = (plist)malloc(sizeof(Node));
if(NewNode == NULL)exit(0);
head->next = NewNode;
NewNode->next = After;
NewNode->data = val;
rt = true;
return rt;
}
bool Insert_tail(plist head,Elemtype val)
{
bool rt = false;
plist After = head;
for(;After->next != NULL;After = After->next);
plist NewNode = (plist)malloc(sizeof(Node));
if(NewNode == NULL)exit(0);
NewNode->next = NULL;
After->next = NewNode;
NewNode->data = val;
rt = true;
return rt;
}
plist Search_Node(plist head,Elemtype val)
{
plist pre = head;
for(;pre->next!=NULL;pre = pre->next)
{
if(pre->next->data == val)
{
return pre;
}
}
return NULL;
}
bool Dele_Node(plist head,Elemtype val)
{
bool rt = false;
plist pre = Search_Node(head,val);
if(pre != NULL)
{
plist pAfter = pre->next;
pre->next = pAfter->next;
free(pAfter);
rt = true;
}
return rt;
}
int Getlength(plist head)
{
int count = 0;
plist pCur = head;
while(pCur!= NULL)
{
count++;
pCur = pCur ->next;
}
return count;
}
void Clear(plist head)
{
plist pCuer = head->next;
plist pAfter = pCuer;
while(pCuer)
{
pAfter = pCuer->next;
free(pCuer);
pCuer = pAfter;
}
head->next = NULL;
}
void Destory(plist head)
{
Clear(head);
free(head);
head = NULL;
}
void Reverse(plist head)//逆置链表初始为空,表中节点从原链表中依次“删除”,再逐个插入逆置链表的表头(即“头插”到逆置链表中),使它成为逆置链表的“新”的第一个结点,如此循环,直至原链表为空。
{
bool rt = false;
plist pCur = head->next;
head->next = NULL;
plist pAfter = pCur;
while(pCur)
{
pAfter = pCur->next;
pCur->next = head->next;
head->next = pCur;
pCur = pAfter;
}
}
void Show(plist head)
{
plist pre = head->next;
while(pre)
{
printf("%d ",pre->data);
pre = pre->next;
}
printf("\n");
}