关于有头结点和无头结点的单链表

来源:互联网 发布:网络教育学士学位证 编辑:程序博客网 时间:2024/04/27 20:12
今天说一下单链表的有头结点和无头结点的操作,其中有一些细节还是需要注意的.废话不多说直接用代码说吧。(先把代码放这)

//这是一个无头结点的单链表
typedef int ElemType;//这里用typedef的作用是在后期便于更改数据类型
typedef struct Node
{
ElemType data;
struct Node*next;
}Node;//定义了个结构体,里面就个数据域和next域

void Init(Node**p)
{
(*p)=NULL;//因为没有头结点,所以只需将(*p)置为NULL即可。
}

void Insert(Node**p,ElemType val)//这里的插入方法使用的最常用的尾插法
{
Node*newnode=(Node*)malloc(sizeof(Node));//首先是创建一个新节点
newnode->data=val;
newnode->next=NULL;//新节点里存放我们要插入的数据,并且将它的next域制成NULL
if((*p)==NULL)
{
(*p)=newnode;//这里判断的含义是指如果这个单链表里一个数都没有,那么就让newnode节点成为它第一个节点。
return ;
}
Node*q=*p;
while(q->next!=NULL)
{
q=q->next;
}
q->next=newnode;//如果它里面有数,那么就这里创建了一个q来遍历整个单链表,最后遍历到这个链表的结尾,然后将这个数插入到最后面
}

bool Delete(Node**p,ElemType val)
{
if( (*p)==NULL)
{
return false;//这里判断的是如果单链表里没有数,那么当然也就没法删除了
}
Node*q=(*p);
if((*p)->data==val)
{
Node*q=(*p);
(*p)=(*p)->next;
free(q);
return true//这个if语句的含义是如果第一个数就是我要删除的那个数,那么就让p指向p->next,然后释放掉q
}
for(Node*q=(*p);q->next !=NULL;q=q->next)//如果走到这一步则说明不是第一个数,然后就是往后遍历直到找到这个数
{
if(q->next->data==val)
{
Node*pCur=q->next;
q->next=pCur->next;
free(pCur);
return true;//这里是删除节点的步骤,思想就是指向下一个的下一个节点
}
}
return false;//如果没找到这个数,就返回false
}

bool Clear(Node**ps)
{
if( (*ps)==NULL)
{
return false;
}//当然,还是要判断,如果单链表是空的,那就返回false;
Node*pCur=*ps;
Node*q=*ps;
while(q->next!=NULL)//只要q->next!=NULL,那么就说明还是节点
{
pCur=q->next;
free(q);
q=pCur;
}//这里的步骤就是从头开始一个一个删,直到最后只有一个节点后就返回
free(pCur);//这就是把最后一个节点删了
(*ps)=NULL;
return true;
}

void Show(Node**ps)//这就是打印函数
{
for(Node*q=*ps;q!=NULL;q=q->next)
{
printf(“%d “,q->data);
}
printf(“\n”);
}

void main()
{
Node*ps;
Init(&ps);
for(int i=0;i<3;i++)
{
Insert(&ps,i);
}
Show(&ps);
Delete(&ps,0);
Show(&ps);
Clear(&ps);
Show(&ps);
}

运行的截图放这:这里写图片描述

接下来我们再来说一说有头结点的单链表
void InitList(List plist)
{
assert(plist!=NULL);
//plist->data;//不用初始化它的data域
plist->next = NULL;
}

//头插
bool Insert_head(List plist,int val)
{
Node p = (Node )malloc(sizeof(Node));
p->data = val;//还是创建一个节点还存放我们要用的数据
p->next = plist->next;
plist->next = p; //插入的时候先连接p和plist->next,然后再连接plist和p
return true;
}
这里写图片描述
//尾插
bool Insert_tail(List plist,int val)
{
Node p = (Node )malloc(sizeof(Node));
p->data = val;

Node *q;for(q=plist;q->next!=NULL;q=q->next) ;//找尾节点//将p插入在q的后面p->next = q->next;//p->next = NULL;q->next = p;return true;

}

Node *Search(List plist,int key)//这是查找函数,若找到目标数据,则返回该节点
{
for(Node *p=plist->next;p!=NULL;p=p->next)
{
if(p->data == key)
{
return p;
}
}
return NULL;
}

bool Delete(List plist,int key)
{
Node *p;
for(p=plist;p->next!=NULL;p=p->next)
{
if(p->next->data == key)
{
break;
}
}
if(p->next == NULL)//没有key
{
return false;
}

//将节点从链表中删除Node *q = p->next;p->next = q->next;//p->next = p->next->next;free(q);//释放内存return true;

}

bool IsEmpty(List plist)
{
return plist->next == NULL;
}

//得到数据节点个数
int GetLength(List plist)
{
int count = 0;

for(Node *p=plist->next;p!=NULL;p=p->next){    count++;}return count;

}

void Show(List plist)
{
for(Node *p=plist->next;p!=NULL;p=p->next)//p->next!=NULL
{
printf(“%d “,p->data);
}
printf(“\n”);
}

void Destroy(List plist)
{
//总是删除第一个数据节点
Node *p;
while(plist->next != NULL)
{
p = plist->next;
plist->next = p->next;
free(p);
}
}

void Clear(List plist)
{
Destroy(plist);
}

void main()
{
Node ps;
InitList(&ps);
for(int i=0;i<5;i++)
{
Insert_head(&ps,i);
}
Show(&ps);
for(int j=5;j<10;j++)
{
Insert_tail(&ps,j);
}
Show(&ps);
}//这后面的和之前说到的无头结点的单链表内容都是一样的,所以不再啰嗦。
来张截图瞅瞅这里写图片描述

最后,做一点总结吧,说说这两种方法的优缺点吧,有头结点的单链表肯定是比较好理解的,但它也会浪费一点资源,然而对于无头结点的就是代码稍微微的能难一点,但其中的好处则是不言而喻的,节省资源这一点其实并不是亮点,我个人认为它更好的一点是没有头结点的阻碍,比如说连接两个链表,你无头结点的就可以直接连接,但像有头结点的,它就要处理头结点这个问题。其实吧,都差不多,就是看个人习惯。
原创粉丝点击