单链表带头结点&不带头结点

转自:http://blog.csdn.net/xlf13872135090/article/details/8857632

Node *head;  //声明头结点

带头结点初始化

void InitList(Node **head){

*head=(Node *)malloc( sizeof(Node));

(*head)->next=NULL;

}

带头结点尾插入,统一操作

方式一:

void CreatList(Node **head){
     Node *r=*head,*s;
     int a;
     while(scanf("%d",&a)){
          if(a!=0){
               s=(Node *)malloc(sizeof(Node));
               s->value=a;
               r->next=s;
               r=s;    
          }
          else{    
               r->next=NULL;
               break;    
          }
     }
}

调用CreatList(&head);

方式二:

void CreatList(Node *head){
     Node *r=head,*s;
     ... //下面的都一样
}

调用CreatList(head);

------------------------------------------------------------------------------------------------------

不带头结点初始化

方式一:

void InitList(Node **head){

*head=NULL;

}

调用InitList(&head);

方式二:

void InitList(Node *head){

head=NULL;

}

调用InitList(head);

不带头结点尾插入,第一个节点与其他节点分开操作

void CreatList(Node  **head){
     Node *p,*t;         /*p工作指针,t临时指针*/
     int a,i=1;
     while(scanf("%d",&a)){
          if(a!=0){
               t=(Node *)malloc(sizeof(Node));
               t->value=a;
               if(i==1){
                    *head=t;    
               }
               else{
                    p->next=t;
               }
               p=t;
          }
          else{    
               p->next=NULL;
               break;    
          }
          i++;
     }
}

调用CreatList(&head);

一、两者区别:

1、不带头结点的单链表对于第一个节点的操作与其他节点不一样,需要特殊处理,这增加了程序的复杂性和出现bug的机会,因此,通常

在单链表的开始结点之前附设一个头结点。

2、带头结点的单链表,初始时一定返回的是指向头结点的地址,所以一定要用二维指针,否则将导致内存访问失败或异常。

3、带头结点与不带头结点初始化、插入、删除、输出操作都不样,在遍历输出链表数据时,带头结点的判断条件是while(head->next!=NULL),

而不带头结点是while(head!=NULL),虽然头指针可以在初始时设定,但是如1所述,对于特殊情况如只有一个节点会出现问题。

二、为什么不带头结点初始化有2种方式,而带头结点只有1种方式呢?

因为不带头结点声明Node *head 时;C编译器将其自动初始化为NULL,于是根本不需要调用InitList(head);也即不带头结点的初始化

是个伪操作。而带头结点的初始化在堆开辟了一段内存,需要修改head指针变量指向的地址(即head的值),所以要修改head的值,必须传保

存head变量的地址(即二维指针)。而直接调用CreatList(head);相当于传head变量的值,函数修改的是head的副本,无法真正改变head的值。

注:这里可以将head指针看成一个变量(不管它保存的是地址),就比较好理解了。

三(key)、其实本质上还是传值,传址的问题,只不过指针本身保存的地址,让这个过程变得有点纠结。在函数调用需要修改指针变量的指向(value)时,

应该传递指针变量的地址(address)。

另外,对于函数的形参是指针时,只要该参数不在左边(即都是右值操作),二维指针(形参)就可以简化为一维指针。如上面带头结点的尾插

简化版本。

时间: 2024-08-03 10:52:55

单链表带头结点&不带头结点的相关文章

带头结点的链表和声明指向第一个元素的头指针

严蔚敏老师的数据结构分析一书中,都是采用带头结点的链表,可能读者一时间还不知道是什么意思:首先看一段伪代码: L是链表的头结点 L=(LinkList)malloc(sizeof(LNode)); L->next=NULL; 链表的头指针也是一个结点,尽管这是一个空的结点,只是说明这个结点并没有携带任何有效的参数. 而我的实现当中确实没有分配一个结点,而只是一个指针,指向第一个元素. typedef struct SNode{     int nData;     SNode* pNextNod

对带头结点的单链表的简单操作

#pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<memory.h> #define DataType int           //int 可以改写为其它数据类型 typedef struct Node { DataType data; struct Node *next; }Node,*pNode;          //定义结点结构体      

C语言实现单链表(带头结点)的基本操作

我在之前一篇博客<C语言实现单链表(不带头结点)的基本操作>中具体实现了不带头结点的单链表的11种操作:如计算链表长度.初始化.创建链表.清空链表等等.但是在实际使用中,带头结点的单链表往往比不带头结点的单链表用的更多,使用也更为方便.因为不用单独考虑第一个节点的情况了,第一个节点和其他后续节点的处理全都一样了,简化操作.这篇博客将会来实现带头结点的单链表的11种操作.代码上传至: https://github.com/chenyufeng1991/LinkedList_HeadNode  .

*循环单链表(不带头结点)

记忆精简:不带头结点,需要创建n个结点,包括三个指针,头指针head,一个游标指针p和创建结点的s.... void creat(List &L,int n) { int e; List s,p; L=NULL; for(int i=1;i<=n;i++)/*n个结点*/ { s=(List)malloc(sizeof(Node)); cin>>e; s->data=e; if(L==NULL) L=s; else p->next=s; p=s; } p->ne

C语言实现双向非循环链表(带头结点尾结点)的节点插入

对于双向链表,个人推荐使用带头结点尾结点的方式来处理会比较方便.我在<C语言实现双向非循环链表(不带头结点)的节点插入>中详细实现了在不带头结点的情况下的插入.这次我们将会来在使用头结点尾结点的情况下在任意的位置插入元素.代码上传至 https://github.com/chenyufeng1991/InsertNodeDoubleLinkedList_HeadNode . 核心代码如下: //插入一个节点 //插入位置分别为0,1,2,..... int InsertNodeList(Nod

在不同的数据结构中链表是否带头结点的分析

一.链表 学习数据结构链表的时候,就有区分 带头结点的链表和不带头结点的链表 当时写完带头结点的链表的基本操作算法后,又写了一遍不带头结点的链表的基本操作. 发现是否带头结点的区别主要体现在2个操作的算法上:插入和删除 不带头结点的链表的插入和删除操作因为涉及对第一个结点插入删除,会改变头指针的值,需要对第一个结点单独分析,链表头指针形参上也因此上加入引用或者指针. 所以相对带头结点的链表操作上不带头结点的链表会更加麻烦. 插入算法上的差异: 1 //带头结点的链表 2 int insert(L

带头结点的单链表操作说明

一.单链表简介 相对于以数组为代表的"顺序表"而言,单链表虽然存储密度比较低(因为数据域才是我们真正需要的,指针域只是用来索引,我们并不真正需要它),但是却具有灵活分配存储空间.方便数据元素的删除.方便元素插入等优点 单链表是线性表链式存储的一种,其储存不连续.单链表的数据结构中包含两个变量:数据和指向下一结点的指针.一个结点只知道下一个结点的地址.一个单链表必须有一个头指针,指向单链表中的第一个结点.否则链表会在内存中丢失. 一般的链表可以不带头结点,头指针直接指向第一个节点,如下图

不带头结点的链表的增删改查

这两天都在学习数据结构中的链表操作,觉得有很多东西想跟大家分享,通常写链表一般会创建一个带头结点的链表,带头结点链表非常容易的进行链表的遍历,而不带头结点的链表,一马虎就会指错,所以在这里跟大家分享下我进行没有头结点的创建时的心得! 1.创建无头结点链表(头插) 2.删除中间节点(不是第一个也不是最后一个) 1 #include<stdio.h> 2 #include<malloc.h> 3 typedef char ElemType; 4 typedef struct node

链表不带头结点的实现

首先要强调的是,ADT没有变化,只是实现上的变化. 不带头结点的实现比带头结点的实现稍微复杂一些,尤其体现在插入(第58-60行)和删除(第88-91行),要单独处理表头改变的情况.而带头结点的链表表头不会变化,总是指向头结点. 其他操作的不同之处同学们自行比较. 下面的问题会帮助你的理解: 第83行 while(p && j < i - 1) {   而教材上带头结点的实现为while(p->next && j < i - 1) { 为什么会有这种区别?