在上篇我简单实现了静态顺序表和动态顺序表,静态来实现一下另一个数据结构
链表是一种线性表,但是并不是顺序存储,而是每个节点里面存储着下一个节点的指针,把存储数据元素的数据串联起来。每个节点都是一个结构体,每个结构体里面存放着一个数据data,以及一个指向下一个节点的next指针。链表的底层不需要所有的空间都连续,只要通过指针就可以找到下一个存储空间。
不带头节点的实现比带头节点的实现相对要稍微复杂一点,因为带头节点的单链表的实现不用对头结点进行各种操作,不用改变头结点,而不带头节点的单链表就需要改变头指针。链表指针直接指向了首元节点,因此在首元节点前插入数据元素或者删除首元节点元素都会改变头指针的值。所以这里要引入二级指针。
头结点的存在是为了方便操作,针对单链表来说,如果带头结点的话,头指针指向头结点,头结点指向首结点;如果不带头结点的话,头指针指向首结点,如果进行插入和删除操作,必须要注意是否是在链表头进行,要分情况处理,而带头结点的不用分情况,比较方便。
1、不带头的单链表的实现
Linklist.h:
#ifndef __LINKLIST_H__
#define __LINKLIST_H__
#include
#include
#include
#include
typedef int Datatype;
typedef struct Node{
Datatype data; //数据
struct Node* next; //指向下一个节点的指针
}Node,*pNode;
pNode BuyNode(Datatype key);
//增删查改
void PushBack(pNode* ppHead, Datatype key);
void PopBack(pNode* ppHead);
void PushFront(pNode* ppHead, Datatype key);
void PopFront(pNode* ppHead);
//在pos的前面进行操作
void Insert(pNode* ppHead, pNode pos, Datatype key);
void Erase(pNode* ppHead, pNode pos);
pNode Find(pNode pHead, Datatype key);
void PrintList(pNode pHead);
#endif
Linklist.c
#include"LinkList.h"
pNode BuyNode(Datatype key)
{
pNode node = (Node*)malloc(sizeof(Node));
node->data = key;
node->next = NULL;
return node;
}
void PushBack(pNode* ppHead, Datatype key)
{
if (*ppHead == NULL)
{ //空链表,直接插入
*ppHead = BuyNode(key);
}
else
{ //链表不为空,找到最后一个节点,然后再插入到最后一个节点的后面
pNode tail = *ppHead;
while (tail->next)
{
tail = tail->next;
}
tail->next = BuyNode(key);
}
}
void PopBack(pNode* ppHead)
{
if (*ppHead == NULL) //空链表
return;
else if ((*ppHead)->next == NULL) //只有一个节点,直接释放
{
free(*ppHead);
*ppHead = NULL;
}
else
{ //一个以上节点
pNode pre = NULL;
pNode cur = *ppHead;
while (cur->next != NULL)
{
pre = cur;
cur = cur->next;
}
pre->next = NULL;
free(cur);
cur = NULL;
}
}
void PushFront(pNode* ppHead, Datatype key)
{
if (*ppHead == NULL)//空链表
{
*ppHead = BuyNode(key);
}
else//不为空
{
pNode NewNode = BuyNode(key);
NewNode->next = *ppHead;
*ppHead = NewNode;
}
}
void PopFront(pNode* ppHead)
{
if (*ppHead == NULL)//空链表
return;
else if ((*ppHead)->next == NULL)//只有一个节点
{
free(*ppHead);
*ppHead = NULL;
}
else//有多个节点
{
/*pNode cur = *ppHead;
*ppHead = cur->next;
free(cur);
cur = NULL;*/
pNode next = (*ppHead)->next;
free(*ppHead);
*ppHead = next;
}
}
void Insert(pNode* ppHead,pNode pos, Datatype key)
{ //在pos后面插入一个节点
assert(pos);
pNode tmp = BuyNode(key);
if (pos == *ppHead) //pos为第一个节点位置时,头插
PushFront(ppHead, key);
else
{ //pos为链表中其他位置,就先找pos所在的前一个节点,
pNode pre = *ppHead;
while (pre->next != pos)
{
pre = pre->next;
} //找到后插入到pre的与pos的中间
tmp->next = pos;
pre->next = tmp;
}
}
void Erase(pNode* ppHead, pNode pos)
{
assert(pos);
if (pos == *ppHead)
PopFront(ppHead);
else if (pos->next == NULL)
PopBack(ppHead);
else
{
pNode pre = *ppHead;
while (pre->next != pos)
{
pre = pre->next;
}
pNode deleteNode = pos;
pre->next = deleteNode->next;
free(deleteNode);
deleteNode = NULL;
}
}
pNode Find(pNode pHead, Datatype key)
{
pNode cur = pHead;
while (cur!= NULL)
{
if (cur->data == key)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
void PrintList(pNode pHead)
{
pNode cur = pHead;
if (cur == NULL)
return;
while (cur!= NULL)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include "LinkList.h"
void test1()
{
Node* list = NULL;
PushBack(&list, 1);
PrintList(list);
PushBack(&list, 2);
PushBack(&list, 3);
PrintList(list);
PushBack(&list, 4);
PushBack(&list, 5);
PrintList(list);
PopBack(&list);
PrintList(list);
}
void test2()
{
Node* list = NULL;
PushFront(&list, 5);
PrintList(list);
PushFront(&list, 4);
PushFront(&list, 3);
PrintList(list);
PushFront(&list, 2);
PushFront(&list, 1);
PrintList(list);
PopFront(&list);
PrintList(list);
PopFront(&list);
PrintList(list);
PopFront(&list);
PrintList(list);
PopFront(&list);
PrintList(list);
PopFront(&list);
PrintList(list);
PopFront(&list);
PrintList(list);
}
void test3()
{
Node* list = NULL;
pNode pos = NULL;
PushBack(&list, 1);
PrintList(list);
PushBack(&list, 2);
PushBack(&list, 4);
PrintList(list);
PushBack(&list, 5);
PushBack(&list, 6);
PrintList(list);
pos = list;
pos = pos->next->next;
Insert(&list,pos,3);
PrintList(list);
pos = Find(list,3);
if (pos)
Erase(&list, pos);
/*if (pos)
pos->data = 30;*/
PrintList(list);
}
int main()
{
test3();
system("pause");
return 0;
}
2、带头节点单链表的实现:
带头节点的链表操作起来比较方便。
LinkList.h
#ifndef __LINKLIST_H__
#define __LINKLIST_H__
#include
#include
#include
#include
typedef int Datatype;
typedef struct Node{
Datatype data; //数据
struct Node* next; //指向下一个节点的指针
}Node;
void InitList(Node **pHead); //初始化单链表
Node* BuyNode(Datatype key); //创建新节点
void PrintList(Node*pHead); //打印单链表
void ClearList(Node *pHead); //清空单链表
int SizeList(Node *pHead); //求链表长度
int IsemptyList(Node *pHead); //判断是否为空链表
Node* Find(Node *pHead, Datatype key); //查找某个元素
void PushBack(Node *pHead, Datatype key);//尾插一个元素
void PopBack(Node *pHead); //尾删一个元素
void PushFront(Node *pHead, Datatype key); //头插一个元素
void PopFront(Node *pHead); //头删一个元素
void DelList(Node* pHead, Node* pos); //指定位置删除
LinkList.c
#include"LinkList.h"
Node* BuyNode(Datatype key) //创建新节点
{
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = key;
newNode->next = NULL;
return newNode;
}
void InitList(Node **pHead) //初始化单链表
{
*pHead = (Node*)malloc(sizeof(Node));
if (*pHead == NULL)
return;
else
(*pHead)->next = NULL;
}
void PrintList(Node*pHead) //打印单链表
{
Node* cur = pHead->next;
if (cur == NULL)
{
return;
}
while (cur != NULL)
{
printf("%d -> ", cur->data);
cur = cur->next;
}
printf("\n");
}
int IsemptyList(Node *pHead) //判断是否为空链表
{
assert(pHead);
Node*tmp = pHead->next;
if (tmp == NULL)
return -1;
else
return 1;
}
Node* Find(Node *pHead, Datatype key) //查找某个元素
{
assert(pHead);
Node* cur = pHead->next;
while (cur != NULL)
{
if (cur->data == key)
return cur;
else
cur = cur->next;
}
return NULL;
}
void PushBack(Node *pHead, Datatype key)//尾插一个元素
{
assert(pHead);
Node* node = BuyNode(key);
Node* tail = pHead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = node;
node->next = NULL;
}
void PopBack(Node *pHead) //尾删一个元素
{
assert(pHead);;
Node* tail = pHead;
Node* pre = NULL;
while (tail->next != NULL)
{
pre = tail;
tail = tail->next;
}
pre->next = NULL;
free(tail);
tail = NULL;
}
void PushFront(Node *pHead, Datatype key) //头插一个元素
{
assert(pHead);
Node* node = BuyNode(key);
Node* cur = pHead->next;
pHead->next = node;
node->next = cur;
}
void PopFront(Node *pHead)
{
assert(pHead);
Node* del = pHead->next;
Node* cur = del->next;
pHead->next = cur;
free(del);
del = NULL;
}
int SizeList(Node *pHead) //求链表长度
{
assert(pHead);
Node* cur = pHead;
int count = 0;
while (cur->next != NULL)
{
count++;
cur = cur->next;
}
return count;
}
void ClearList(Node *pHead) //清空单链表
{
assert(pHead);
Node* cur = pHead;
while (cur->next != NULL)
{
PopFront(pHead);
}
pHead = NULL;
}
void DelList(Node* pHead, Node* pos) //指定位置删除
{
Node* cur = pHead;
if (pos == (cur->next))
PopFront(pHead);
else if (pos->next == NULL)
PopBack(pHead);
else
{
while (cur->next != pos)
{
cur = cur->next;
}
if (cur->next == pos)
{
Node* Next = pos->next;
cur->next = Next;
free(pos);
pos = NULL;
}
}
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include "LinkList.h"
void test1()
{
Node*list;
InitList(&list);
PrintList(list);
PushBack(list, 1);
PushBack(list, 2);
PushBack(list, 3);
PrintList(list);
PopBack(list);
PrintList(list);
}
void test2()
{
Node*list;
InitList(&list);
PrintList(list);
PushFront(list, 1);
PushFront(list, 2);
PushFront(list, 3);
PrintList(list);
PopFront(list);
PrintList(list);
}
void test3()
{
Node*list;
int ret = 0;
InitList(&list);
PrintList(list);
PushFront(list, 1);
PushFront(list, 2);
PushFront(list, 3);
PushFront(list, 4);
PushFront(list, 5);
PrintList(list);
ret=SizeList(list);
printf("链表长度为%d\n", ret);
PopFront(list);
SizeList(list);
PrintList(list);
}
void test4()
{
Node*list;
Node*pos;
InitList(&list);
PrintList(list);
PushFront(list, 1);
PushFront(list, 2);
PushFront(list, 3);
PushFront(list, 4);
PushFront(list, 5);
PrintList(list);
pos = Find(list, 3);
DelList(list, pos);
PrintList(list);
}
int main()
{
test4();
system("pause");
return 0;
}