本文共 2726 字,大约阅读时间需要 9 分钟。
链表是一种常见的数据存储结构,其特点是通过指针连接一系列数据节点,形成线性数据存储单元。每个节点带有一个指针usex],指向下一个节点。区别于数组,链表不会因为数据量增加而频繁内存分配带来的性能问题,适合动态数据存储场景。
链表结构具有灵活的增删操作能力,但在单次随机访问时性能较差。
链表可以分为两种形式:一种是带有头节点的链表,头节点不存储数据;另一种则是无头节点的链表,数据插入最前面。
实现一个无头链表的具体步骤如下:
定义节点结构体:包含数据域和指针域 .NODE { int a; struct Node *pNext; }
分配头节点:使用malloc分配一个节点的空间,赋值pHead和pEnd为这个节点
逐步添加数据节点:在头节点的后面依次建立新的数据节点,将前一个节点的指针指向新节点
#include#include struct Node { int a; struct Node *pNext;};struct Node *g_pHead = NULL;struct Node *g_pEnd = NULL;void AddNodeToList(int a) { struct Node *pTemp = (struct Node *)malloc(sizeof(struct Node)); pTemp->a = a; pTemp->pNext = NULL; if (g_pHead == NULL || g_pEnd == NULL) { g_pHead = g_pEnd = pTemp; } else { g_pEnd->pNext = pTemp; g_pEnd = pTemp; }}
链表支持两种插入方式:尾插法和头插法。
PIR: pEnd
PIR: g_pHead
链表节点的删除需要注意以下几点:
单向链表删除算法:
void delete(int a) { struct Node *p = g_pHead; while (p != NULL) { if (a == p->pNext->a) { struct Node *nextNode = p->pNext; p->pNext = nextNode->pNext; free(nextNode); break; } p = p->pNext; }}
这一步骤释放的空间可以通过打印被删除节点的a值来验证空间释放成功。
双向链表每个节点包含两个指针:一个指向前一个节点(prev),另一个指向后一个节点(next)。双向链表优势:
双向链表节点结构定义:
typedef struct node { struct node *prev; int a; struct node *next;};
新节点创建:
NODE* createnode(int a) { NODE* node = (NODE*)malloc(sizeof(NODE)); node->prev = NULL; node->a = a; node->next = NULL; return node;}
添加节点(尾部插入):
void add2list(NODE* head, NODE* new_node) { if (head == NULL) { head->prev = head->next = new_node; return; } new_node->prev = head->prev; new_node->next = head; head->prev->next = new_node; head->prev = new_node;}
在循环链表中,链表的头节点和尾节点以双向链接的方式相连(即:pEnd->next = pHead)。这种结构特点是节点数量有限闭环操作。常见应用:
分类讨论:
静态链表采用数组的形式模拟链表,节点通过数组索引访问查找。优点:
静态链表示例:
#define carriage_RETURNtypedef struct { int data; int next;} SNode;SNode StaticList[11]; // 最大存储空间int add_data(int a) { size_t position = 0; do { position++; if (position >= sizeof(StaticList)/sizeof(SNode)) position = 0; StaticList[position].data = a; } while (false);}
主要考量事项:
该结构通过数组模拟指针的灵活性,在开发效率上有特定优势,但数据操作的范围有限。
转载地址:http://galoz.baihongyu.com/