数据结构c语言实现-链表(带和不带头节点)

本文详细介绍了使用C语言实现链表的两种方式:带头结点和不带头结点的链表,并对比了这两种实现方式在插入和删除操作上的差异。通过具体代码示例,展示了如何进行节点的插入、删除及遍历等基本操作。

                                                                                                   数据结构与算法分析——c语言描述


第3章   第二节   表

1.带头结点(原书)   稍微改造一下

#include <stdio.h>
#include <stdlib.h>
struct Node;
typedef struct Node *PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;

typedef int ElementType;
struct Node 
{
   ElementType Element;
   Position Next;
};

void FatalError(const char *s)
{
    printf("%s", s);
     exit(-1);
}
int IsEmpty(List L)
{
   return L->Next == NULL;
}

int IsLast(Position P, List L)
{
     return P->Next == NULL;
}

Position Find(ElementType X, List L)
{
     Position P;
  
     P = L->Next;
     while(P != NULL && P->Element != X)
        P = P->Next;
  
    return P;
}

Position FindPrevious(ElementType X, List L)
{
    Position P;
    
    P = L;
    while(P->Next != NULL && P->Next->Element != X)
             P = P->Next;

    return P;
}

void Delete(ElementType X, List L)
{
   Position P, TmpCell;
   
    P = FindPrevious(X, L);

   if(! IsLast(P, L))
      {
         TmpCell = P->Next;
       P->Next = TmpCell->Next;
       free(TmpCell);
       
      }
}

void Insert(ElementType X, List L, Position P)
{
     Position TmpCell;
   
     TmpCell = (Position)malloc(sizeof(struct Node));
     if(!TmpCell)
        FatalError("Out of space!");
      

     TmpCell->Element = X;
     TmpCell->Next = P->Next;
     P->Next = TmpCell;
}

void Destroy(List L)
{
    Position P;
     while(L)
     {
       P = L;
      L = L->Next;
      free(P);
     }
}

void Travel(List L)
{
    while(L->Next)
    {
         printf("%d ", L->Next->Element);
         L = L->Next;
    }
    
    printf("\n");
}

int main(void)
{

    List L = (List)malloc(sizeof(struct Node));
    if(!L)
       FatalError("Out of space!");
  
     int i;
     Position P = L;
     for(i = 1; i <= 5; i++)
      {
           /*  Insert(i, L, P);              //尾插
              P = P->Next; */      
            Insert(i, L, L);
      }
      
    P = L;
     
      Travel(L);
      int n;
      printf("Input the number you want to delete:");
       scanf("%d", &n);
      Delete(n , L);
     Travel(L);
       Destroy(L);
    
    return 0;
}


2.不带头结点

#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;
struct Node
{
  ElemType data;
  struct Node *next;
};

typedef struct Node* Pnode;

void Insert(Pnode *p, int data, int i)
{
      int j = 1;
      Pnode pp = *p;
      if(i == 1)
      {
          *p = (Pnode)malloc(sizeof(struct Node));
          (*p)->data = data;
         (*p)->next = pp;
       return ;
      }
      
     
      while(pp && j < i -1)
        {
            pp = pp->next;
                j++;
        }  
   
        if(!pp)
        {
          printf("Out of bordor!\n");
          exit(-1);
        }  
    Pnode s = (Pnode)malloc(sizeof(struct Node));
       s->data = data;
    s->next = pp->next;
    pp->next = s;
}

void Delete(Pnode *p, int i)
{
   int j = 1;
   Pnode temp = *p, t;
   if(i == 1)
   {
      *p = temp->next;
       free(temp);
       return ;
   }
 
   while(temp && j < i - 1)
   {
        temp = temp->next;
         j++;
      
   }
  
   if(!temp)
   {
     printf("Outer of bordor!\n");
      exit(-1);
   }

   t = temp->next;
   temp->next = t->next;
   free(t);
}

void Travel(Pnode p)
{
    while(p)
    {
       printf("%d ", p->data);
       p = p->next;
    }
  printf("\n");
}

void Destroy(Pnode p)
{
   Pnode temp;

    while(p)
    {
       temp = p;
        p = p->next;
       free(temp);
    }
 
  
}

int main()
{
   Pnode p = NULL;
    int i = 1;
   
   for(; i <= 5; i++)
   {
     
      Insert(&p, i, i);
   }
  
   Travel(p);
   printf("Input the location you want to delete:");
   int n;
   scanf("%d", &n);
   Delete(&p, n);
    Travel(p);
   Destroy(p);
   return 0;
}


3.个人总结

    插入删除是表操作里的重点内容,而链表的插入和删除要把握好“前一个”概念,要操作当前节点,必须要找到它的前一个节点的指针。

     带头节点的链表在对第一个节点操作时明显优于不带头结点的的链表!

<think>好的,我现在需要回答用户关于C语言中计算带头节点带头节点的单链表长度的问题。首先,我需要回忆单链表的基本结构,以及带头节点带头节点的区别。带头节点链表通常有一个存储实际数据的头节点,其next指针指向第一个有效节点;而带头节点链表则直接以第一个有效节点作为头指针。 接下来,用户需要示例代码来计算这两种链表的长度。我需要确保代码正确,并且符合C语言的语法。对于带头节点链表遍历时应该从头节点的下一个节点开始,直到遇到NULL为止。对于带头节点链表遍历则直接从第一个节点开始。 我还需要注意用户提供的引用内容。引用[3]中提到了一个统计链表有效结点个数的函数,这个函数是针对循环链表的,但遍历逻辑类似,只是终止条件同。引用[2][4]也提到了链表长度计算的方法,但可能需要调整以适应单链表的结构。 在编写代码时,我需要确保指针操作正确,避免空指针解引用。例如,处理带头节点链表时,如果链表本身为空(头指针为NULL),则长度应该为0。而带头节点链表即使没有有效节点,头节点本身也存在,所以需要从头节点的next开始判断。 另外,用户希望示例代码分别展示带头节点带头节点的情况,所以需要分开两个函数或者两种情况来处理。同时,代码注释要清晰,说明每个步骤的作用,以便用户理解。 可能还需要考虑边界情况,比如链表为空的情况,以及只有一个节点的情况,确保代码在这些情况下也能正确运行。例如,当带头节点链表节点的next为NULL时,长度应为0;而带头节点链表头指针为NULL时,长度同样为0。 最后,生成相关问题时要围绕链表操作,可能涉及初始化、插入删除操作,或者链表类型的长度计算差异等,帮助用户深入理解单链表的应用实现。</think>### C语言实现计算带头节点/带头节点链表长度的方法 #### 一、带头节点的单链表长度计算 **核心逻辑**:从头节点的下一个结点开始遍历,直到遇到`NULL` ```c int getLengthWithHead(LinkList *head) { int count = 0; LinkList *p = head->next; // 跳过头节点 while (p != NULL) { count++; p = p->next; } return count; } ``` **特点**: 1. 头节点存储有效数据[^4] 2. 空链表时返回0(head->next == NULL) --- #### 二、带头节点的单链表长度计算 **核心逻辑**:从第一个有效节点开始遍历 ```c int getLengthWithoutHead(LinkList *head) { int count = 0; LinkList *p = head; // 直接从头指针开始 while (p != NULL) { count++; p = p->next; } return count; } ``` **特点**: 1. 当链表为空时`head == NULL`,直接返回0 2. 需要处理空指针情况[^3] --- #### 三、使用示例 ```c // 带头节点链表 LinkList *head = createListWithHead(); printf("长度:%d", getLengthWithHead(head)); // 带头节点链表 LinkList *head2 = createListWithoutHead(); printf("长度:%d", getLengthWithoutHead(head2)); ``` --- #### 四、关键差异对比 | 特性 | 带头节点 | 带头节点 | |-------------------|---------------------|---------------------| | 空链表判断 | head->next == NULL | head == NULL | | 插入首节点 | 无需特殊处理 | 需要修改头指针 | | 删除首节点 | 无需特殊处理 | 需要修改头指针 | | 代码复杂度 | 较低 | 较高 |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值