8-6 案例:单链表的基本实现

1. 单链表的基本形式

 2. 链表节点的结构体

        需要注意 typedef 可以将结构体重命名。此外,单链表由数据域和指针域组成。

// 节点结构体
typedef struct ListNode{
  int value;
  struct ListNode* next;
}ListNode;

3. 创建单链表节点

        申请空间后,需要对空间进行判断,确保空间申请成功。

// 创建节点
ListNode* CreateNode(int value){

  // 申请空间
  ListNode * node = malloc(sizeof(ListNode));

  // 申请空间失败
  if(!node) exit(1);

  node->value = value;
  node->next = NULL;

  return node;
}

4. 销毁单链表节点

        销毁节点时,需要注意的是节点指针也要置为NULL,所以在函数传参时,需要将节点指针的指针传入函数,这样才能修改节点指针的值。

// 销毁节点,需要注意的是,节点的指针也要在函数中置为NULL,所以要传入节点指针的指针
void DestroyNode(ListNode** node_ptr){

  // 节点的操作
  (*node_ptr)->next = NULL;
  free(*node_ptr);

  // 节点指针置NULL
  *node_ptr = NULL;
}

5. 创建单链表

        注意,代码默认头结点的数据域无效,所以头结点的下一节点才开始存储传入的参数。

// 创建单链表
ListNode *CreateList(int array[], int length){

  if(length <= 0) return 0;

  // 创建头结点
  ListNode *head = CreateNode(0);

  ListNode *cur = head;
  for (int i = 0; i < length; ++i) {
    cur->next = CreateNode(array[i]);
    cur = cur->next;
  }

  return head;
}

6. 销毁单链表

        由于销毁单独节点时,需要将节点指针置为NULL,故此处也传入二维指针。特别注意的是,头结点指针也要置为NULL,不能忘记。

// 销毁单链表, 由于节点指针需要置为NULL,传入二维指针
void DestroyList(ListNode **head){

  // 如果节点指针不存在或者节点指针的指针不存在,直接退出
  if(!head || !(*head)) return;

  ListNode *cur = *head;

  // 移动之后,把上一个节点清除
  while(cur){

    // 一旦节点销毁,节点的指针也会被置为NULL,所以需要创建一个临时的节点指针
    ListNode *temp = cur;

    cur = cur->next;

    DestroyNode(&temp);
  }

  // 特别注意,使用的*head要置为NULL,不能让其成为野指针
  *head = NULL;
}

7. 打印单链表

// 打印单链表
void PrintList(ListNode *head){

  // 头结点不存在
  if (!head) return;

  // 头结点存在
  ListNode *cur = head;
  while(cur->next){
    printf("%d,", cur->next->value);
    cur = cur->next;
  }
}

8. 插入单链表节点

        需要注意的是,如果插入位置前面没有节点,默认用值为 -1 的节点进行补齐。此外补齐节点的代码 cur->next = CreateNode(-1),可以好好看看。

void InsertList(ListNode *head, int index, int num){

  if(!head || index < 0) return;

  // 新节点一直都在
  ListNode *new_node = CreateNode(num);

  ListNode *cur = head;

  // 如果不是插入新节点
  while(index > 0){

    // index不为0,需要补齐-1节点
    if(!cur->next){
      cur->next = CreateNode(-1);  // 妙处在于这句话,新建节点,并且相连了
    }
    cur = cur->next;
    index--;
  }

  // 插入新节点
  new_node->next = cur->next;
  cur->next = new_node;
}

9. 删除单链表节点

        删除单链表中所有元素值为 value 的节点,不是删除第一个值为 value 的节点。

// 删除单链表节点,根据传入的value值删除对应节点
void DeleteNode(ListNode **head, int value){

  // 如果头结点的指针或者头结点不存在,没法删除
  if(!head || !(*head)) return;

  ListNode *cur = *head;

  // 一直遍历
  while(cur->next){

    // 找到待删除的节点
    if(cur->next->value != value){
      cur = cur->next;
    }else{

      // 删除这一节点
      ListNode *to_be_delete = cur->next;
      cur->next = to_be_delete->next;
      DestroyNode(&to_be_delete);
    }
  }
}

 10. 验证

int main(){

  int array[5] = {1,2,3,4,5};

  ListNode *head = CreateList(array, 5);
  PrintList(head);

  printf("\n插入之后:");
  InsertList(head, 7, -22);
  PrintList(head);

  printf("\n删除之后:");
  DeleteNode(&head, -5);
  PrintList(head);

  DestroyList(&head);
  printf("\n销毁之后:");
  PrintList(head);
  return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值