大家都不陌生,一个程序员,语言是基础,数据结构是核心之一,因此,
在学习过程中必须反复练习,那么今天我们来看看对与数据结构中,链表的实现。
首先,我们要明确,在线性表中有两类,一是顺序表,分为动态顺序表和静态顺序表,
我们前面有介绍静态,二是链表,链表又分为八种,即:
1.不带头不带环单向链表。(学习)
2.带头不带环单向链表。
3.不带头带环单向链表。
4.带头带环单向链表。
5.不带头不带环双向链表。
6.带头不带环双向链表。
7.不带头带环双向链表。
8.带头带环双向链表。(常用)
这八种基本相似,但在学习阶段都需要练习,今天我把我练习的,不带头不带环单项链表。
一下为代码的声明。
#pragma once
#include<stdio.h>
#include<stdlib.h>
#define DIV_LINE printf("\n\n===========%s==========\n\n",__FUNCTION__);
typedef char TypeChar;
typedef struct LinkNode
{
TypeChar data;
struct LinkNode *next;
}LinkNode;
//对单链表进行初始化
void InitLinkNode(LinkNode **head);
//打印
void LinkNodePrint(LinkNode *head);
//创建节点
LinkNode *CreatNode(TypeChar value);
//对单链表进行尾插;
LinkNode* PushBackLinkNode(LinkNode** head, TypeChar Value);
//对单链表进行尾删
void PopBackLinkNode(LinkNode** head);
//对单链表进行头插
void PushFrontLinkNode(LinkNode** head, TypeChar Value);
//对单链表进行头删
void PopFrontLinkNode(LinkNode** head);
//对单链表进行值位置的查找,返回对应值的地址
LinkNode* FindLinkNode(LinkNode* head, TypeChar value);
//在链表的指定位置之前插入元素,普通放方法,时间复杂度O(n)
void InsertFrontLinkNode(LinkNode** head, LinkNode* pos, TypeChar value);
//在链表的指定位置之前插入元素。(移花接木大法)时间复杂度为o(1).
void InsertFrontLinkNode1(LinkNode** head, LinkNode* pos, TypeChar value);
//在单链表指定位置之后插入元素。
void InsertAfterLinkNode(LinkNode* head, LinkNode* pos, TypeChar value);
//删除单链表中任意指定位置的节点。时间复杂度为o(n)
void EraseLinkNode(LinkNode** head, LinkNode* pos);
//删除单链表中指定位置的节点,(除过尾节点)时间复杂度为o(1).
void EraseLinkNode1(LinkNode* head, LinkNode* pos);
//删除指定值的节点,(在无头单链表中第一个出现的值的节点)
void RemoveLinkNode(LinkNode** head, TypeChar value);
//删除指定值的所有元素。
void RemoveLinkNodeAll(LinkNode** head, TypeChar value);
//判断链表是否为空
int EmotyLinkNode(LinkNode* head);
//求链表长度
size_t SizeLinkNode(LinkNode* head);
//将链表逆序打印
void BackPrintLinkNode(LinkNode* head);
代码的实现:
#include"LinkNode.h"
//打印
void LinkNodePrint(LinkNode *head)
{
LinkNode* cur = NULL;
printf("head:");
if(head == NULL)
{
//空链表。
return;
}
cur = head;
while(cur != NULL)
{
printf("[%c:%p]-> ",cur->data,&cur->data);
cur = cur->next;
}
printf("NULL\n\n");
}
//对单链表进行初始化
void InitLinkNode(LinkNode **head)
{
if (head == NULL)
{
// 非法输入。
return;
}
*head = NULL;
}
//创建节点
LinkNode *CreatNode(TypeChar value)
{
LinkNode* new_node = (LinkNode *)malloc(sizeof(LinkNode));
if(new_node == NULL)
{
//申请内存失败。
return NULL;
}
new_node->next = NULL;
new_node->data = value;
return new_node;
}
//对单链表进行尾插;
LinkNode* PushBackLinkNode(LinkNode **head, TypeChar value)
{
LinkNode *new_node = NULL;
LinkNode *cur = NULL;
if(head == NULL)
{
//非法输入
return NULL;
}
new_node = CreatNode(value);
if(*head == NULL)
{
*head = new_node;
return *head;
}
cur = *head;
while(cur->next != NULL)
{
cur = cur->next;
}
cur->next = new_node;
return new_node;
}
//对单链表进行尾删
void PopBackLinkNode(LinkNode **head)
{
LinkNode* to_delete = NULL;
LinkNode* cur = *head;
if (head == NULL)
{
//非法输入。
return ;
}
if (*head == NULL)
{
//为空链表。
return;
}
if ((*head)->next == NULL)
{
free(*head);
*head = NULL;
return;
}
while (cur->next->next != NULL)
{
cur = cur->next;
}
to_delete = cur->next;
free(to_delete);
cur->next = NULL;
return;
}
//对单链表进行头插
void PushFrontLinkNode(LinkNode** head, TypeChar value)
{
LinkNode* cur = NULL;
if (head == NULL)
{
//非法输入。
return;
}
cur = CreatNode(value);
cur->next = *head;
*head = cur;
}
//对单链表进行头删
void PopFrontLinkNode(LinkNode** head)
{
LinkNode* cur = NULL;
if (head ==NULL)
{
//非法输入。
return;
}
if (*head == NULL)
{
//为空列表。
return;
}
cur = (*head)->next;
free(*head);
*head = cur;
}
//对单链表进行值位置的查找,返回对应值的地址
LinkNode* FindLinkNode(LinkNode* head, TypeChar value)
{
LinkNode* cur = NULL;
if (head == NULL)
{
//空链表。
return NULL;
}
cur = head;
while (cur != NULL)
{
if (cur->data == value)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
//在链表的指定位置之前插入元素,普通放方法,时间复杂度O(n)
void InsertFrontLinkNode(LinkNode** head, LinkNode* pos, TypeChar value)
{
LinkNode* new_node = NULL;
LinkNode* cur = NULL;
if (head == NULL || pos == NULL)
{
//非法输入。
return;
}
if (*head == NULL)
{
//单链表为空。
return;
}
cur = *head;
if (cur == pos) //对头节点进行判断,是否是pos.
{
PushFrontLinkNode(head, value);
return;
}
while (cur->next != NULL)
{
if (cur->next == pos)
{
new_node = CreatNode(value);
cur->next = new_node;
new_node->next = pos;
return;
}
cur = cur->next;
}
return;
}
//在链表的指定位置之前插入元素。(移花接木大法)时间复杂度为o(1).
void InsertFrontLinkNode1(LinkNode** head, LinkNode* pos, TypeChar value) //pos值必须要是合法节点
{
LinkNode* new_node = NULL;
if (head == NULL || pos == NULL)
{
//非法输入。
return;
}
if (*head == NULL)
{
//链表为空。
return;
}
new_node = CreatNode(pos->data);
new_node->next = pos->next;
pos->next = new_node;
pos->data = value;
}
//在单链表指定位置之后插入元素。
void InsertAfterLinkNode(LinkNode* head, LinkNode* pos, TypeChar value)
{
// 因为是在单链表之后插入元素,所以不会改变头指针,所以用* 而不用**
LinkNode* new_node = NULL;
if (head == NULL || pos == NULL)
{
//链表为空链表。
return;
}
new_node = CreatNode(value);
new_node->next = pos->next;
pos->next = new_node;
return;
}
//删除单链表中任意指定位置的节点。时间复杂度为o(n)
void EraseLinkNode(LinkNode** head, LinkNode* pos)
{
LinkNode* cur = NULL;
if (head == NULL || pos == NULL)
{
// 非法输入。
return;
}
if (*head == NULL)
{
//链表为空。
return;
}
if (*head == pos)
{
*head = (*head)->next;
free(pos);
return;
}
cur = *head;
while (cur->next != NULL)
{
if (cur->next == pos)
{
cur->next = pos->next;
pos->next = NULL;
break;
}
cur = cur->next;
}
free(pos);
}
//删除单链表中指定位置的节点,(除过尾节点)时间复杂度为o(1).
void EraseLinkNode1(LinkNode* head, LinkNode* pos)
{
LinkNode* temp = NULL;
if (head == NULL || pos == NULL)
{
//链表为空,pos非法。
return;
}
temp = pos->next;
pos->data = temp->data;
pos->next = temp->next;
free(temp);
return;
}
//删除指定值的节点,(在无头单链表中第一个出现的值的节点)
void RemoveLinkNode(LinkNode** head, TypeChar value)
{
LinkNode* cur = NULL;
LinkNode* temp = NULL;
if (head == NULL)
{
//非法输入。
return ;
}
if (*head == NULL)
{
//空链表。
return ;
}
cur = *head;
if (cur->data == value) //头节点。
{
*head = (*head)->next;
free(cur);
return ;
}
while (cur->next != NULL)
{
if (cur->next->data == value)
{
temp = cur->next; //赋值一定要注意保存原来指针指向的地址,以便于释放内存。
cur->next = cur->next->next;//不明白画图。
free(temp);
break;
}
cur = cur->next;
}
}
//删除指定值的所有元素。
void RemoveLinkNodeAll(LinkNode** head, TypeChar value)
{
LinkNode* pos = NULL;
int ret = 1;
while (ret)
{
pos = FindLinkNode(*head, value);
if (pos == NULL)
{
ret = 0;
}
EraseLinkNode(head, pos);
}
//LinkNode* cur = NULL;
//LinkNode* temp = NULL;
//LinkNode* keep = NULL;
//LinkNode* sb = NULL;
//if (head == NULL)
//{
// // 非法输入。
// return;
//}
//if (*head == NULL)
//{
// // 空链表。
// return;
//}
//temp = *head;
//if ((*head)->data == value)
//{
// *head = (*head)->next;
// free(temp);
//}
//keep = *head;
//cur = (*head)->next;
//while (cur->next != NULL)
//{
// if (cur->data == value)
// {
// keep->next = cur->next;
// sb = cur;
// }
// else
// {
// keep = keep->next;
// }
// cur = cur->next;
// free(sb);
//}
}
//判断链表是否为空
int EmotyLinkNode(LinkNode* head)
{
if (head == NULL)
{
return 1;
}
return 0;
}
//求链表长度
size_t SizeLinkNode(LinkNode* head)
{
size_t count = 0;
LinkNode* cur = NULL;
cur = head;
while (cur != NULL)
{
++count;
cur = cur->next;
}
return count;
}
//将链表逆序打印
void BackPrintLinkNode(LinkNode* head)
{
if (head == NULL)
{
//为空链表。
return;
}
BackPrintLinkNode(head->next);
printf("[%c: %p]",head->data,head);
}
以下是代码的测试。。
#include"LinkNode.h"
void TestInit()
{
LinkNode *head = NULL;
DIV_LINE;
InitLinkNode(&head);
}
void TestPushBackLinkNode()
{
LinkNode *head = NULL;
DIV_LINE;
InitLinkNode(&head);
PushBackLinkNode(&head,'a');
PushBackLinkNode(&head,'b');
PushBackLinkNode(&head,'c');
PushBackLinkNode(&head,'d');
LinkNodePrint(head);
}
void TestPopBackLinkNode()
{
LinkNode *head = NULL;
DIV_LINE;
InitLinkNode(&head);
PopBackLinkNode(&head);
PushBackLinkNode(&head,'a');
PushBackLinkNode(&head,'b');
PushBackLinkNode(&head,'c');
PushBackLinkNode(&head,'d');
PopBackLinkNode(&head);
PopBackLinkNode(&head);
LinkNodePrint(head);
PopBackLinkNode(&head);
LinkNodePrint(head);
PopBackLinkNode(&head);
LinkNodePrint(head);
}
void TestPushFrontLinkNode()
{
LinkNode *head = NULL;
DIV_LINE;
InitLinkNode(&head);
PushFrontLinkNode(&head, 'y');
LinkNodePrint(head);
PushBackLinkNode(&head, 'a');
PushBackLinkNode(&head, 'b');
PushBackLinkNode(&head, 'c');
PushFrontLinkNode(&head, 'x');
LinkNodePrint(head);
}
void TestPopFrontLinkNode()
{
LinkNode *head = NULL;
DIV_LINE;
InitLinkNode(&head);
PopFrontLinkNode(&head);
LinkNodePrint(head);
PushBackLinkNode(&head, 'a');
PushBackLinkNode(&head, 'b');
PushBackLinkNode(&head, 'c');
PopFrontLinkNode(&head);
PopFrontLinkNode(&head);
LinkNodePrint(head);
PopFrontLinkNode(&head);
LinkNodePrint(head);
}
void TestFindLinkNode()
{
LinkNode* pos = NULL;
LinkNode* temp = NULL;
LinkNode* head = NULL;
DIV_LINE;
InitLinkNode(&head);
PushBackLinkNode(&head,'a');
pos = PushBackLinkNode(&head,'b');
PushBackLinkNode(&head,'c');
PushBackLinkNode(&head,'d');
temp = FindLinkNode(head,'b');
printf("expect %p,actual %p\n",pos,temp);
}
//o(n)
void TestInsertFrontLinkNode()
{
LinkNode* pos = NULL;
LinkNode* temp = NULL;
LinkNode* head = NULL;
DIV_LINE;
InitLinkNode(&head);
temp = PushBackLinkNode(&head,'a');
pos = PushBackLinkNode(&head,'b');
PushBackLinkNode(&head,'c');
PushBackLinkNode(&head,'d');
LinkNodePrint(head);
InsertFrontLinkNode(&head,pos,'x');
LinkNodePrint(head);
InsertFrontLinkNode(&head,temp,'y');
LinkNodePrint(head);
InsertFrontLinkNode(&head,NULL,'8');
LinkNodePrint(head);
}
void TestInsertFrontLinkNode1()
{
LinkNode* pos = NULL;
LinkNode* temp = NULL;
LinkNode* head = NULL;
DIV_LINE;
InitLinkNode(&head);
temp = PushBackLinkNode(&head,'a');
pos = PushBackLinkNode(&head,'b');
PushBackLinkNode(&head,'c');
PushBackLinkNode(&head,'d');
LinkNodePrint(head);
InsertFrontLinkNode1(&head,pos,'x');
LinkNodePrint(head);
InsertFrontLinkNode1(&head,temp,'y');
LinkNodePrint(head);
InsertFrontLinkNode1(&head,NULL,'8');
LinkNodePrint(head);
}
void TestInsertAfterLinkNode()
{
LinkNode* pos = NULL;
LinkNode* temp = NULL;
LinkNode* head = NULL;
DIV_LINE;
InitLinkNode(&head);
temp = PushBackLinkNode(&head,'a');
pos = PushBackLinkNode(&head,'b');
PushBackLinkNode(&head,'c');
PushBackLinkNode(&head,'d');
LinkNodePrint(head);
InsertAfterLinkNode(head,pos,'x');
LinkNodePrint(head);
InsertAfterLinkNode(head,temp,'y');
LinkNodePrint(head);
InsertAfterLinkNode(head,NULL,'8');
LinkNodePrint(head);
}
void TestEraseLinkNode()
{
LinkNode* pos = NULL;
LinkNode* temp = NULL;
LinkNode* head = NULL;
DIV_LINE;
InitLinkNode(&head);
temp = PushBackLinkNode(&head,'a');
pos = PushBackLinkNode(&head,'b');
PushBackLinkNode(&head,'c');
PushBackLinkNode(&head,'d');
LinkNodePrint(head);
EraseLinkNode(&head,pos);
LinkNodePrint(head);
EraseLinkNode(&head,temp);
LinkNodePrint(head);
}
void TestEraseLinkNode1() //采用换值不换位置的方法,所以pos的地址如果不正确,程序奔溃。
{
LinkNode* pos = NULL;
LinkNode* temp = NULL;
LinkNode* head = NULL;
DIV_LINE;
InitLinkNode(&head);
temp = PushBackLinkNode(&head,'a');
pos = PushBackLinkNode(&head,'b');//在删除temp时候,pos已经被删除。
PushBackLinkNode(&head,'c');
PushBackLinkNode(&head,'d');
EraseLinkNode1(head,temp);
LinkNodePrint(head);
EraseLinkNode1(head,temp);
LinkNodePrint(head);
}
void TestRemoveLinkNode()
{
int ret = 0;
LinkNode *head = NULL;
DIV_LINE;
InitLinkNode(&head);
PushBackLinkNode(&head, 'a');
PushBackLinkNode(&head, 'b');
PushBackLinkNode(&head, 'c');
PushBackLinkNode(&head, 'd');
LinkNodePrint(head);
RemoveLinkNode(&head,'b');
RemoveLinkNode(&head,'d');
LinkNodePrint(head);
RemoveLinkNode(&head,'a');
LinkNodePrint(head);
}
void TestRemoveLinkNodeAll()
{
LinkNode *head = NULL;
DIV_LINE;
InitLinkNode(&head);
PushBackLinkNode(&head, 'd');
PushBackLinkNode(&head, 'a');
PushBackLinkNode(&head, 'd');
PushBackLinkNode(&head, 'c');
PushBackLinkNode(&head, 'd');
PushBackLinkNode(&head, 'c');
PushBackLinkNode(&head, 'd');
PushBackLinkNode(&head, 'd');
LinkNodePrint(head);
RemoveLinkNodeAll(&head, 'd');
LinkNodePrint(head);
}
void TestEmotyAndSzie()
{
int ret = 0;
size_t temp = 0;
LinkNode *head = NULL;
DIV_LINE;
InitLinkNode(&head);
ret = EmotyLinkNode(head);
printf("except 1 actual %d\n",ret); //是空返回1,不是空返回0.
PushBackLinkNode(&head, 'd');
PushBackLinkNode(&head, 'a');
PushBackLinkNode(&head, 'd');
PushBackLinkNode(&head, 'c');
PushBackLinkNode(&head, 'd');
PushBackLinkNode(&head, 'c');
PushBackLinkNode(&head, 'd');
PushBackLinkNode(&head, 'd');
temp = SizeLinkNode(head);
printf("except 8 actual %d\n",temp);
}
void TestBackPrintLinkNode()
{
LinkNode *head = NULL;
DIV_LINE;
InitLinkNode(&head);
PushBackLinkNode(&head, 'a');
PushBackLinkNode(&head, 'b');
PushBackLinkNode(&head, 'c');
PushBackLinkNode(&head, 'd');
BackPrintLinkNode(head);
}
int main()
{
TestInit();
TestPushBackLinkNode();
TestPopBackLinkNode();
TestPushFrontLinkNode();
TestPopFrontLinkNode();
TestFindLinkNode();
TestInsertFrontLinkNode();
TestInsertFrontLinkNode1();
TestInsertAfterLinkNode();
TestEraseLinkNode();
TestEraseLinkNode1();
TestRemoveLinkNode();
TestRemoveLinkNodeAll();
TestEmotyAndSzie();
TestBackPrintLinkNode();
return 0;
}
链表的增删查改。。如有不足,希望多多指导。。