数据结构:链表详解与应用

目录

单向链表

特点

linklist.h

main.c

linklist.c

循环链表

双向链表


单向链表

解决顺序存储的缺点:插入、删除和动态存储问题。

动态存储:程序运行起来后,决定链表的容量。内存的使用率相对比较高。

特点

一组任意的存储单位存储线性表的数据元素,存储单元可以是连续的,也可以不连续;可以被存储在任意内存未被占用的位置上。

在链表中存储数据,数据域、指针域(自己的下一个在哪里):节点

linklist.h

cpp 复制代码
#ifndef __LINKLIST__H__
#define __LINKLIST__H__

typedef struct person
{
  char name[32];
  int age;
  char sex;

  int score;
} DATATYPE;

typedef struct node
{
  DATATYPE data;
  struct node *next;
} LinkNode;

typedef struct list
{
  LinkNode *head;
  int clen;
} LinkList;

LinkList *CreateLinkList();
int InsertHeadLinkList(LinkList *list, DATATYPE *data);
int InsertTailLinkList(LinkList *list, DATATYPE *data);
int ShowLinkList(LinkList *list);
LinkNode *FindLinkList(LinkList *list, char *name);
int DeleteLinkList(LinkList *list, char *name);
int ModifyLinkList(LinkList *list, char *name, DATATYPE *newdata);
int DestroyLinkList(LinkList *list);
int IsEmptyLinkList(LinkList* list);
int GetSizeLinkList(LinkList* list);
void RevertLinkList(LinkList *list);
LinkNode* FindMidList(LinkList* list);
LinkNode* FindLastklist(LinkList* list,int k);
#endif  //!__LINKLIST__H__

main.c

cpp 复制代码
#include <stdio.h>
#include "linklist.h"

int main(int argc, char** argv)
{
  LinkList* ll = CreateLinkList();  // ll指针是实参
  DATATYPE data[] = {
      {"zhangsan", 20, 'f', 90}, {"lisi", 21, 'm', 92},   {"wangmazi", 30, 'm', 80},
      {"guanerge", 50, 'm', 70}, {"liubei", 55, 'm', 98},
  };
  /*
    InsertHeadLinkList(ll, &data[0]);
    InsertHeadLinkList(ll, &data[1]);
    InsertHeadLinkList(ll,&data[2]);
    InsertHeadLinkList(ll, &data[3]);
  */

  InsertTailLinkList(ll, &data[0]);
  InsertTailLinkList(ll, &data[1]);
  InsertTailLinkList(ll, &data[2]);
  InsertTailLinkList(ll, &data[3]);
  InsertTailLinkList(ll, &data[4]);
  ShowLinkList(ll);

  //   printf("---------------------find-------------------\n");
  //   LinkNode* ret = FindLinkList(ll, "zhangsan");
  //   if (NULL == ret)
  //   {
  //     printf("can't find person\n");
  //   }
  //   else
  //   {
  //     printf("find it,name:%s score: %d\n", ret->data.name, ret->data.score);
  //   }

  //   printf("---------------------delete-------------------\n");
  //   DeleteLinkList(ll, "guanerge");
  //   ShowLinkList(ll);

  //   printf("---------------------modify-------------------\n");
  //   ModifyLinkList(ll, "lisi", &data[2]);
  //   ShowLinkList(ll);

  //   printf("-----------------------revert-----------------------\n");
  //   RevertLinkList(ll);
  //   ShowLinkList(ll);

  //   DestroyLinkList(ll);
  //   ll = NULL;

  //   printf("-------------------fine mid-------------------\n");
  //   FindMidList(ll);
  //   LinkNode* ret = FindMidList(ll);
  //   if (NULL == ret)
  //   {
  //     printf("can't fine mid\n");
  //   }
  //   else
  //   {
  //     printf("find it,name:%s\n", ret->data.name);
  //   }

  printf("----------------find lastk----------------\n");
  LinkNode* ret = FindLastklist(ll, 4);
  if (NULL == ret)
  {
    printf("can't find lastk\n");
  }
  else
  {
    printf("find it,name:%s\n", ret->data.name);
  }

  return 0;
}

linklist.c

cpp 复制代码
#include "linklist.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * @brief Create a Link List object创建一个单向链表头结构
 *
 * @return LinkList* 指向单向链表表头结构的指针
 */
LinkList *CreateLinkList()
{
  LinkList *ll = malloc(sizeof(LinkList));
  if (NULL == ll)
  {
    printf("create malloc error\n");
    return NULL;
  }
  ll->head = NULL;
  ll->clen = 0;
  return ll;
}

/**
 * @brief 单向链表的头插操作
 *
 * @param list 待操作的链表
 * @param data 需要新增的数据
 * @return int 0成功 1失败
 */
int InsertHeadLinkList(LinkList *list, DATATYPE *data)
{
  LinkNode *newnode = malloc(sizeof(LinkNode));
  if (NULL == newnode)
  {
    printf("inserthead malloc error\n");
    return 1;
  }
  memcpy(&newnode->data, data, sizeof(DATATYPE));
  newnode->next = NULL;
  newnode->next = list->head;
  list->head = newnode;
  list->clen++;
  return 0;
}

/**
 * @brief 在链表的最后新增元素
 *
 * @param list 待操作的链表
 * @param data 需要新增的数据
 * @return int 0成功 1失败
 */
int InsertTailLinkList(LinkList *list, DATATYPE *data)
{
  if (IsEmptyLinkList(list))
  {
    return InsertHeadLinkList(list, data);
  }
  LinkNode *newnode = malloc(sizeof(LinkNode));
  if (NULL == newnode)
  {
    printf("insert malloc error\n");
    return 1;
  }
  memcpy(&newnode->data, data, sizeof(DATATYPE));
  newnode->next = NULL;
  LinkNode *tmp = list->head;
  while (tmp->next)
  {
    tmp = tmp->next;
  }
  tmp->next = newnode;
  list->clen++;
  return 0;
}

/**
 * @brief 显示单向链表中的数据
 *
 * @param list  待操作的单向链表表头指针
 * @return int 0成功
 */
int ShowLinkList(LinkList *list)
{
  LinkNode *tmp = list->head;  // 这里的指针指向head的地址,形参
  while (NULL != tmp)
  {
    printf("name:%s age:%d ssex:%c score:%d\n", tmp->data.name, tmp->data.age, tmp->data.sex, tmp->data.score);
    tmp = tmp->next;
  }
  return 0;
}

/**
 * @brief 按照名字查找下一个节点
 *
 * @param list 需要被查找的链表
 * @param name 需要被查找的名字
 * @return LinkNode*  NULL失败  !=NULL成功
 */
LinkNode *FindLinkList(LinkList *list, char *name)
{
  LinkNode *tmp = list->head;
  int len = GetSizeLinkList(list);
  int i = 0;
  for (i = 0; i < len; i++)
  {
    if (0 == strcmp(tmp->data.name, name))
    {
      return tmp;
    }
    tmp = tmp->next;
  }
  return NULL;
}

int DeleteLinkList(LinkList *list, char *name)
{
  if (IsEmptyLinkList(list))
  {
    printf("delete error\n");
    return 1;
  }
  LinkNode *tmp = NULL;
  LinkNode *prev = NULL;
  if (0 == strcmp(list->head->data.name, name))
  {
    tmp = list->head;
    list->head = list->head->next;
    free(tmp);
    list->clen--;
    return 0;
  }
  else
  {
    tmp = list->head;
    prev = list->head;
    while (1)
    {
      tmp = tmp->next;
      if (NULL == tmp)
      {
        break;
      }
      if (0 == strcmp(tmp->data.name, name))
      {
        prev->next = tmp->next;
        free(tmp);
        list->clen--;
        return 0;
      }
      prev = tmp;
    }
  }
  return 1;
}
/**
 * @brief
 *
 * @param list 根据节点名字修改的内容
 * @param name 需要被修改的用户名
 * @param newdata
 * @return int
 */

int ModifyLinkList(LinkList *list, char *name, DATATYPE *newdata)
{
  if (IsEmptyLinkList(list))
  {
    printf("delete error\n");
    return 1;
  }
  LinkNode *tmp = FindLinkList(list, name);
  memcpy(&tmp->data.name, newdata, sizeof(DATATYPE));

  return 0;
}

/**
 * @brief 释放链表占用的内存(表头+节点)
 *
 * @param list 需要被释放的链表的表头指针
 * @return int 0成功 1失败
 */
int DestroyLinkList(LinkList *list)
{
  if (list == NULL)
  {
    free(list);
    return 1;
  }

  LinkNode *tmp = list->head;

  while (tmp != NULL)
  {
    list->head = tmp->next;
    free(tmp);
    tmp = tmp->next;
  }

  free(list->head);
  free(list);
  return 0;
}

int IsEmptyLinkList(LinkList *list)
{
  return 0 == list->clen;
}
int GetSizeLinkList(LinkList *list)
{
  return list->clen;
}

/**
 * @brief 单向链表的逆序
 *
 * @param list 待操作的链表
 */
void RevertLinkList(LinkList *list)
{
  if ((IsEmptyLinkList(list)) || (1 == GetSizeLinkList(list)))
  {
    printf("no need revert\n");
    return;
  }
  LinkNode *prev = NULL;
  LinkNode *curr = list->head;
  LinkNode *last = NULL;

  while (curr != NULL)
  {
    last = curr->next;
    curr->next = prev;
    prev = curr;
    curr = last;
  }
  list->head = prev;
}

/**
 * @brief 查找链表中间节点
 *
 * @param list 需要被操作的链表
 * @return LinkNode*  NULL 失败,!=NULL 找到的指针
 */
LinkNode *FindMidList(LinkList *list)
{
  LinkNode *fast = list->head;
  LinkNode *slow = list->head;
  while (fast)
  {
    fast = fast->next;
    if (NULL == fast)
    {
      break;
    }
    slow = slow->next;
    fast = fast->next;
  }
  return slow;
}

/**
 * @brief 查找链表第k个节点
 * 
 * @param list 待操作的链表的表头指针
 * @param k 倒数第k个节点
 * @return LinkNode* NULL失败   
 */
LinkNode *FindLastklist(LinkList *list, int k)
{
  LinkNode *fast = list->head;
  LinkNode *slow = list->head;
  while (k)
  {
    fast = fast->next;
    k--;
  }
  while (fast)
  {
    slow = slow->next;
    fast = fast->next;
  }
  return slow;
}

双向链表

doublelink.h

cpp 复制代码
#ifndef __DOULINK__H__
#define __DOULINK__H__

typedef struct person
{
    char name[32];
    int age;
    char sex;
    int score;
} DATATYPE;

typedef struct dounode
{
    DATATYPE data;
    struct dounode *prev;
    struct dounode *next;
} DouLinkNode;

typedef struct list
{
    DouLinkNode *head;
    int clen;
} DouLinkList;

typedef enum {DIR_FORWARD,DIR_BACKWARD}DIRECT;

DouLinkList *CreateDouLinkList();
int InsertHeadDouLinkList(DouLinkList *dl,DATATYPE* data);
int ShowDouLinkList(DouLinkList *dl,DIRECT dir);
int InserTailDouLinkList(DouLinkList *dl,DATATYPE* data);
DouLinkNode* FindDouLinkList(DouLinkList *dl,char *name);
int ModifyDouLinkList(DouLinkList *dl,char *name,DATATYPE* newdata);
int DeleteDouLinkList(DouLinkList *dl,char *name);
int IsEmptyDouLinkList(DouLinkList *dl);
int GetSizeDouLinkList(DouLinkList *dl);
int DestroyDouLinkList(DouLinkList *dl);

#endif  
相关推荐
2013编程爱好者7 小时前
【C++】树的基础
数据结构·二叉树··二叉树的遍历
NEXT067 小时前
二叉搜索树(BST)
前端·数据结构·面试
化学在逃硬闯CS7 小时前
Leetcode1382. 将二叉搜索树变平衡
数据结构·算法
季明洵10 小时前
Java实现单链表
java·开发语言·数据结构·算法·单链表
elseif12311 小时前
【C++】ST表求RMQ问题--代码+分析
数据结构·c++·算法
tju新生代魔迷12 小时前
数据结构:栈和队列
数据结构
Bear on Toilet12 小时前
树_构建多叉树_41 . 实现Trie(前缀树)
开发语言·数据结构·c++·算法·leetcode
这波不该贪内存的14 小时前
双向链表实现与应用详解
数据结构·链表
he___H14 小时前
数组的全排列
java·数据结构·算法
小飞学编程...15 小时前
【阻塞队列 ——Java 】
java·开发语言·数据结构