首先清楚常见的线性表分为:顺序表 链表 栈 队列 字符串。
顺序表是一段物理地址连续的存储单元依次存储数据结构元素的线性结构。一般情况下采用数组存储。顺序存储分为静态存储和动态存储,静态存储采取数组的形式,动态存储采取数组合指针相结合的方法。动态顺序表比较常用,中间/头部的插入和删除时间复杂度为O(n).
链表常见的结构有8种.但是在以后工作上容易用到的是循环链表。在找工作的面试题里面经常用到的是单链表。
下面主要说的是不带头结点单链表的一些基本操作。
1.节点结构。
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode *next;
}SListNode;//节点
typedef struct SList
{
struct SListNode *first;
}SList;//first代表链表第一个节点
不带头单链表节点由两部分组成,节点有两个域,指针域和数据域。另外需要链表去连接每个节点。
2.节点基本操作
初始化
void SListInit(SList *list)
{
assert(list!=NULL);
list->first=NULL;
}
销毁操作
思路就是链表的每一个节点均为空,第一个节点直接赋值为空即可,剩下的所有节点就是释放每个节点。
void SListDestory(SList *list)
{
SListNode *next;
for(SListNode *cur=list->first;cur!=NULL;cur=next)
{
next=cur->next;
free(cur);
}
list->first=NULL;
}
头插
头插的思路很简单:判断链表是否有效 判断新产生的节点是否有效要用到assert函数,其实也可以使用if,另外还要清楚什么时候 用if,什么时候用assert.判断完之后核心语句:新产生节点的指针域是原有链表的第一个节点。再次更新节点。
void SListPushFront(SList *list,SLTDataType data)
{
//产生节点
//判断链表有效性(是否只有一个节点)
assert(list!=NULL);
SListNode *node=(SListNode*)malloc(sizeof(SListNode));
assert(node);//判断节点是否有效很重要
node->data=data;
node->next=list->first;
list->first=node;
}
头删
首先就是链表是否有效,链表的第一个节点是否存在,删除操作,释放节点。一定要释放空间,不然容易内存泄漏。
void SListPopFront(SList *list)
{//头删
assert(list!=NULL);
assert(list->first!=NULL);
SListNode *old_first=list->first;
list->first=list->first->next;
free(old_first);
}
尾插
思路很简单:首先判断链表是否为空,链表的第一个节点是否为空,然后寻找原有的最后一个节点,产生新节点储存,新节点为现在的最后一个节点,相关操作。
void SListPushBack(SList *list,SLTDataType data)
{//尾插
//首先找到最后一个节点,若只有一个节点,相当于头插
assert(list!=NULL);
if(list->first==NULL)
{
SListPushFront(list,data);
return;
}
//寻找最后一个节点
SListNode *lastone=list->first;
for(;lastone->next!=NULL;lastone=lastone->next){
}
SListNode *node=(SListNode*)malloc(sizeof(SListNode));
assert(node);
node->data=data;
node->next=NULL;
lastone->next=node;
}
尾删
基本思路:链表不能为空,链表只有一个节点,链表有两个节点时的情况,相当于头删,链表的节点个数多余2个,寻找链表的倒数第二个节点,寻找到了,释放节点。
void SListPopBack(SList *list)//尾删
{
assert(list!=NULL);
assert(list->first!=NULL);//0个
if(list->first->next==NULL)
//只有一个节点 1个
{
SListPopFront(list);
return;
}
SListNode *cur=list->first;
//寻找倒数第二个节点
for(;cur->next->next!=NULL;cur=cur->next){
}
free(cur->next);
cur->next=NULL;
}
查找
基本思路:遍历单链表,如果当前产生节点的数据域与要查找的数据域相等的话就返回节点的的位置.否则返回空。
SListNode* SListFind(SList *list,SLTDataType data)
{
for(SListNode *cur=list->first;cur!=NULL;cur=cur->next)
{
if(cur->data==data)
{
return cur;
}
}
return NULL;
}
在指定节点后插入
在相关指定节点后插入,产生节点后插入就可以很简单,注意更新。
void SListInsertAfter(SListNode *pos,SLTDataType data)
{
SListNode* node=(SListNode*)malloc(sizeof(SListNode));
node->data=data;
node->next=pos->next;
pos->next=node;
}
删除指定值
首先需要找到对应值的前一个节点,这是第一步,cur是用来遍历的节点,cur==NULL表示没找到。prev==NULL相当于头删。删除操作。
void SListRemove(SList *list,SLTDataType data)
{
//重点是找到data这个结点的前一个结点
//previous prev
SListNode *prev=NULL;
SListNode *cur=list->first;
while(cur!=NULL&&cur->data!=data)
{
prev=cur;
cur=cur->next;
}
//cur==NULL表示没找到
//cur!=NULL;&&prev!=NULL
//cur就是要删除的结点,同时prev就是要删的前一个结点
if(cur==NULL)
{
return;
}
if(prev==NULL)
{
SListPopFront(list);
return;
}
prev->next=cur->next;
free(cur);
}
打印
打印很简单就是遍历后打印即可。
void SListPrint(SList *list)
{
for(SListNode *cur=list->first;cur!=NULL;cur=cur->next)
{
printf("%d-->",cur->data);
}
printf("NULL\n");
}
测试操作
注意传入的是指针还是地址。我个人采用主函数部分直接测试,但是更建议用测试函数这样更保险,寻找错误时能更容易一点。
int main()
{
SList list;
SListInit(&list);
SListPushFront(&list,1);
SListPushFront(&list,2);
SListPrint(&list);
SListPopFront(&list);
SListPrint(&list);
SListPushBack(&list,3);
SListPrint(&list);
SListPopBack(&list);
SListPrint(&list);
SListNode *n1=SListFind(&list,1);
SListInsertAfter(n1,10);
SListPrint(&list);
return 0;
}
这些就是单链表的一些基本操作,开始可能看不太懂,写的多了就会了,写得多了自然就理解了。单链表是以后找工作时很爱考察的点。务必要懂得。我这个单链表跨了一个月才能算差不多合格。
下面贴上完整代码。
#include<iostream>
#include<cstdio>
#include<assert.h>
#include<algorithm>
using namespace std;
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode *next;
}SListNode;//节点
typedef struct SList
{
struct SListNode *first;
}SList;//first代表链表第一个节点
void SListInit(SList *list)
{
assert(list!=NULL);
list->first=NULL;
}
void SListDestory(SList *list)
{
SListNode *next;
for(SListNode *cur=list->first;cur!=NULL;cur=next)
{
next=cur->next;
free(cur);
}
list->first=NULL;
}
void SListPushFront(SList *list,SLTDataType data)
{//头插
//产生节点
//判断链表有效性(是否只有一个节点)
assert(list!=NULL);
SListNode *node=(SListNode*)malloc(sizeof(SListNode));
assert(node);//判断节点是否有效很重要
node->data=data;
node->next=list->first;
list->first=node;
}
void SListPopFront(SList *list)
{//头删
assert(list!=NULL);
assert(list->first!=NULL);
SListNode *old_first=list->first;
list->first=list->first->next;
free(old_first);
}
void SListPushBack(SList *list,SLTDataType data)
{//尾插
//首先找到最后一个节点,若只有一个节点,相当于头插
assert(list!=NULL);
if(list->first==NULL)
{
SListPushFront(list,data);
return;
}
//寻找最后一个节点
SListNode *lastone=list->first;
for(;lastone->next!=NULL;lastone=lastone->next){
}
SListNode *node=(SListNode*)malloc(sizeof(SListNode));
assert(node);
node->data=data;
node->next=NULL;
lastone->next=node;
}
void SListPopBack(SList *list)//尾删
{
assert(list!=NULL);
assert(list->first!=NULL);//0个
if(list->first->next==NULL)
//只有一个节点 1个
{
SListPopFront(list);
return;
}
SListNode *cur=list->first;
//寻找倒数第二个节点
for(;cur->next->next!=NULL;cur=cur->next){
}
free(cur->next);
cur->next=NULL;
}
SListNode* SListFind(SList *list,SLTDataType data)
{
for(SListNode *cur=list->first;cur!=NULL;cur=cur->next)
{
if(cur->data==data)
{
return cur;
}
}
return NULL;
}
void SListInsertAfter(SListNode *pos,SLTDataType data)
{
SListNode* node=(SListNode*)malloc(sizeof(SListNode));
node->data=data;
node->next=pos->next;
pos->next=node;
}
void SListRemove(SList *list,SLTDataType data)
{
SListNode *prev=NULL;
SListNode *cur=list->first;
while(cur!=NULL&&cur->data!=data)
{
prev=cur;
cur=cur->next;
}
if(cur==NULL)
{
return;
}
if(prev==NULL)
{
SListPopFront(list);
return;
}
prev->next=cur->next;
free(cur);
}
void SListPrint(SList *list)
{
for(SListNode *cur=list->first;cur!=NULL;cur=cur->next)
{
printf("%d-->",cur->data);
}
printf("NULL\n");
}
int main()
{
SList list;
SListInit(&list);
SListPushFront(&list,1);
SListPushFront(&list,2);
SListPrint(&list);
SListPopFront(&list);
SListPrint(&list);
SListPushBack(&list,3);
SListPrint(&list);
SListPopBack(&list);
SListPrint(&list);
SListNode *n1=SListFind(&list,1);
SListInsertAfter(n1,10);
SListPrint(&list);
return 0;
}