链表的概念与结构
链表是一种物理存储结构非连续、非顺序的存储结构,数据元素的逻辑顺序是由链表中的指针链接次序实现的
实际中链表结构多样,主要分为以下几种:
单向,双向
循环,非循环
带头,不带头
最常用的有两种:
无头单向非循环链表:结构简单,但实现较复杂,一般不单独存储数据
带头双向循环链表:结构复杂,一般用来单独存储数据。实际中使用的链表数据结构都是带头双向循环链表,因为实现较为简单
链表的实现
- 无头单向不循环链表的实现
SListNode.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SListDataType;
typedef struct SListNode//每个节点是一个结构体
{
SListDataType _data;//数据域
struct SListNode* _next;//指针域
}SListNode;
typedef struct SList
{
SListNode* _head;
}SList;
void SListInit(SList* pcb);
void SListDestroy(SList* pcb);
void SListPushFront(SList* pcb, SListDataType x);//头插
void SListPushBack(SList* pcb, SListDataType x);//尾插
void SListPopFront(SList* pcb);//头删
void SListPopBack(SList* pcb);//尾删
SListNode* SListFind(SList* pcb, SListDataType x);//查找
void SListInsertAfter(SListNode* pos, SListDataType x);//在POS的后面进行插入
void SListEraseAfter(SListNode* pos);//把pos后面的那一个删除
void SListInsertFront(SList* pcb, SListNode* pos, SListDataType x);//在pos的前面进行插入
void SListRemove(SList* pcb, SListDataType x);//找出一组数据中重复数据的第一个进行删除
void SListAllRemove(SList* pcb, SListDataType x);//删除与 X 相同的所有数据
void SListPrint(SList* pcb);//打印
SListNode.c
#include"SListNode.h"
void SListInit(SList* pcb)
{
assert(pcb);
pcb->_head = NULL;
}
void SListDestroy(SList* pcb)
{
assert(pcb);
SListNode* cur = pcb->_head;
SListNode* next = NULL;
while (cur != NULL)
{
next = cur->_next;
free(cur);
cur = next;
}
}
void SListPushBack(SList* pcb, SListDataType x)
{
assert(pcb);
SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
if (newnode == NULL)
{
printf("malloc error");
exit(-1);
}
newnode->_data = x;
newnode->_next = NULL;
if (pcb->_head == NULL)//为空时
{
pcb->_head = newnode;
}
else//非空时
{
SListNode* cur = pcb->_head;
while (cur->_next != NULL)
{
cur = cur->_next;
}
cur->_next = newnode;
}
}
void SListPopBack(SList* pcb)
{
assert(pcb);
SListNode* cur = pcb->_head;
if (cur == NULL)//没有节点时
{
return;
}
else if (cur->_next == NULL)
{
free(cur);
pcb->_head = NULL;
}
else
{
while (cur->_next->_next != NULL)
{
cur = cur->_next;
}
free(cur->_next);
cur->_next = NULL;
}
}
void SListPushFront(SList* pcb, SListDataType x)
{
assert(pcb);
SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
{
if (newnode == NULL)
{
printf("newnode error");
exit(-1);
}
newnode->_data = x;
newnode->_next = NULL;
newnode->_next = pcb->_head;
pcb->_head = newnode;
}
}
void SListPopFront(SList* pcb)
{
assert(pcb);
SListNode* cur = pcb->_head;
if (cur == NULL)
{
return;
}
else
{
pcb->_head = cur->_next;
free(cur);
cur = NULL;
}
}
SListNode* SListFind(SList* pcb, SListDataType x)
{
assert(pcb);
SListNode* cur = pcb->_head;
while (cur != NULL)
{
if (cur->_data == x)
{
return cur;
}
cur = cur->_next;
}
return NULL;
}
void SListInsertAfter(SListNode* pos, SListDataType x)
{
assert(pos);
SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
newnode->_data = x;
newnode->_next = NULL;
newnode->_next = pos->_next;
pos->_next = newnode;
}
void SListEraseAfter(SListNode* pos)
{
assert(pos);
if (pos->_next == NULL)
{
return;
}
else
{
SListNode* next = pos->_next;
pos->_next = next->_next;
free(next);
next = NULL;
}
}
void SListInsertFront(SList* pcb, SListNode* pos, SListDataType x)
{
assert(pcb);
assert(pos);
SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
newnode->_data = x;
newnode->_next = NULL;
SListNode* cur = pcb->_head;
SListNode* pcur = NULL;
while (cur != NULL)
{
if (cur->_data == pos->_data)
{
if (pcur == NULL)
{
pcb->_head = newnode;
newnode->_next = cur;
}
else
{
pcur->_next = newnode;
newnode->_next = cur;
}
return;
}
else
{
pcur = cur;
cur = cur->_next;
}
}
}
void SListRemove(SList* pcb, SListDataType x)
{
assert(pcb);
SListNode* cur = pcb->_head;
SListNode* pcur = NULL;
while (cur != NULL)
{
if (cur->_data == x)
{
if (pcur == NULL)
pcb->_head = cur->_next;
else
pcur->_next = cur->_next;
free(cur);
cur = NULL;
return;
}
else
{
pcur = cur;
cur = cur->_next;
}
}
}
void SListAllRemove(SList* pcb, SListDataType x)
{
assert(pcb);
SListNode* cur = pcb->_head;
SListNode* prev = NULL;
SListNode* next = NULL;
while (cur != NULL)
{
if (cur->_data == x)
{
next = cur->_next;
free(cur);
cur = NULL;
cur = next;
if (prev == NULL)
{
pcb->_head = next;
}
else
{
prev->_next = cur;
}
}
else
{
prev = cur;
cur = cur->_next;
}
}
}
void SListPrint(SList* pcb)
{
assert(pcb);
SListNode* cur = pcb->_head;
while (cur != NULL)
{
printf("%d->", cur->_data);
cur = cur->_next;
}
printf("NULL\n");
}
-
带头双向循环链表
ListNode.h
#pragma once
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* _prev;
struct ListNode* _next;
LTDataType _data;
}ListNode;
typedef struct List
{
ListNode* _head;
}List;
void ListInit(List* plt);
void ListDestory(List* plt);
ListNode* BuyListNode(LTDataType x);
void ListPushFront(List* plt, LTDataType x);
void ListPushBack(List* plt, LTDataType x);
void ListPopFront(List* plt);
void ListPopBack(List* plt);
ListNode* ListFind(List* plt, LTDataType x);
void ListInsert(ListNode* pos, LTDataType x);
void ListErase(ListNode* pos);
void ListRemove(List* plt, LTDataType x);
void ListPrint(List* plt);
ListNode.c
#include"List.h"
ListNode* BuyListNode(LTDataType x)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
newnode->_next = NULL;
newnode->_prev = NULL;
newnode->_data = x;
return newnode;
}
void ListInit(List* plt)
{
assert(plt);
plt->_head = NULL;
}
void ListDestory(List* plt)
{
assert(plt);
ListNode* head = plt->_head;
ListNode* cur = head->_next;
ListNode* next = NULL;
while (cur != head)
{
next = cur->_next;
free(cur);
cur = next;
}
}
void ListPushFront(List* plt, LTDataType x)
{
assert(plt);
ListNode* head = plt->_head;
ListNode* first = head->_next;
ListNode* newnode = BuyListNode(x);
head->_next = newnode;
newnode->_prev = head;
newnode->_next = first;
first->_prev = newnode;
}
void ListPushBack(List* plt, LTDataType x)
{
assert(plt);
ListNode* head = plt->_head;
ListNode* tail = head->_prev;
ListNode* newnode = BuyListNode(x);
head->_prev = newnode;
newnode->_next = head;
newnode->_prev = tail;
tail->_next = newnode;
}
void ListPopFront(List* plt)
{
assert(plt);
ListNode* head = plt->_head;
assert(head->_next != head);
ListNode* first = head->_next;
ListNode* second = first->_next;
free(first);
first = NULL;
head->_next = second;
second->_prev = head;
}
void ListPopBack(List* plt)
{
assert(plt);
ListNode* head = plt->_head;
assert(head->_prev != head);
ListNode* Onetail = head->_prev;
ListNode* Twotail = Onetail->_prev;
free(Onetail);
Onetail = NULL;
head->_prev = Twotail;
Twotail->_next = head;
}
ListNode* ListFind(List* plt, LTDataType x)
{
assert(plt);
ListNode* head = plt->_head;
ListNode* cur = head->_next;
while (cur != head)
{
if (cur->_data == x)
{
return cur;
}
cur = cur->_next;
}
return NULL;
}
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
ListNode* prev = pos->_prev;
ListNode* newnode = BuyListNode(x);
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = pos;
pos->_prev = newnode;
}
void ListErase(ListNode* pos)
{
assert(pos);
ListNode* prev = pos->_prev;
ListNode* next = pos->_next;
free(pos);
pos = NULL;
prev->_next = next;
next->_prev = prev;
}
void ListRemove(List* plt, LTDataType x)
{
assert(plt);
ListNode* head = plt->_head;
ListNode* cur = head->_next;
ListNode* prev = cur->_prev;
ListNode* next = cur->_next;
while (cur != head)
{
if (cur->_data == x)
{
free(cur);
prev->_next = next;
next->_prev = prev;
cur = next;
}
else
{
cur = cur->_next;
}
}
}
void ListPrint(List* plt)
{
assert(plt);
ListNode* head = plt->_head;
ListNode* cur = head->_next;
while (cur != head)
{
printf("[%d]->", cur->_data);
cur = cur->_next;
}
}
链表及顺序表的比较
顺序表
优点:空间连续,支持随机访问
缺点:中间/头部插入删除时间复杂度较高,增容代价大
链表
优点:任意位置插入实践复杂度都为O(1),插入一个开辟一个空间
缺点:以节点为单位存储,不支持随机访问