链表分为带头结点的顺序表和不带头结点的顺序表,按算法来说,不带头结点的顺序表要比带头结点的顺序表复杂一点,涉及到二级指针的用法(形参的改变不会对实参产生影响)。而带头结点的顺序表不会使链表置空,方便操作。
typedef int SLTdataType;
typedef struct ListNode{
struct ListNode*prev;
struct ListNode*next;
SLTdataType data;
};
左侧存放指向前一个的指针,中间为数据域,右边为指向下一个的指针
双向即指同一个结点中不仅有数据域来存放数据,还有next指针指向下一个结点和prev指针指向上一个结点。而对于头结点来说它的prev即phead->prev指向最后一个结点,最后一个结点的next指向头结点。
基本操作
链表的一系列操作都是基于基本操作的基础上实现的,基本操作有初始化、前插、后插、前删、后删、随机删除、随机插入等。
1.初始化
ListNode*BuyListNode(SLTdataType x){
ListNode*newnode=(SLTdataType*)malloc(sizeof(SLTdataType));
if(newnode==NULL)
exit(-1);
else{
newnode->prev=NULL;
newnode->next=NULL;
newnode->data=x;
}
return newnode;
}
ListNode*InitList(){
ListNode*phead=BuyListNode(0);
phead->prev=phead;
phead->next=phead;
return phead;
}
2.前插
void InsertListfront(ListNode*phead,SLTdataType x){
ListNode*newnode=BuyListNode(x);
ListNode*first=phead->next;
phead->next=newnode;
newnode->next=first;
newnode->prev=phead;
first->prev=newnode;
}
3.后插
void InsertListback(ListNode*phead,SLTdataType x){
ListNode*newnode=BuyListNode(x);
ListNode*tail=phead->prev;
tail->next=newnode;
newnode->prev=tail;
phead->prev=newnode;
newnode->next=phead;
}
4.随机插入
void InsertList(ListNode*phead,int pos,SLTdataType x){
ListNode*newnode=BuyListNode(x);
ListNode*prev=phead;
ListNode*cur=phead->next;
for(int i=0;i<pos;i++){
cur=cur->next;
prev=prev->next;
}
newnode->next=cur;
newnode->prev=prev;
prev->next=newnode;
cur->prev=newnode;
}
5.随机删除
void DeleteList(Listnode*phead,int pos){
ListNode*cur=phead->next;
ListNode*prev=phead;
for(int i=0;i<pos;i++){
prev=prev->next;
cur=cur->next;
}
prev->next=cur->next;
cur->next->prev=prev;
free(cur);
}