首先是链表的结构
struct ListNode
{
ListNode(int x):mval(x),pnext(NULL){}
int mval;
ListNode * pnext;
};
初始化
void InitList(ListNode *phead)
{
if(phead == NULL) return ;
phead->pnext = NULL;
}
1.单链表的头插
bool Insert_head(ListNode* phead,int x)
{
if(phead == NULL) return false;
ListNode * p = (ListNode *)malloc(sizeof(ListNode));
p->mval = x;
p->pnext = phead->pnext;
phead->pnext = p;
return true;
}
.2.单链表的尾插
bool Insert_tail(ListNode* phead,int x)
{
if(phead == NULL) return false;
ListNode * p = (ListNode*)malloc(sizeof(ListNode));
ListNode * q=phead;
for(;q->pnext != NULL;q=q->pnext);//比头插多了一次向后遍历找到最后一个节点
p->mval = x;
p->pnext = q->pnext;
q->pnext = p;
return true;
}
3.单链表的查找
ListNode* Search(ListNode *phead,int x)
{
if(phead == NULL) return NULL;
ListNode *p=phead;
for(;p->pnext != NULL;p=p->pnext)
{
if(p->mval == x)//如果是查找前驱,p->pnext->val == x
{
return p;
}
}
return NULL;
}
4.查找待删除节点的前驱
ListNode* SearchPrev(ListNode *phead,ListNode* BeDelete)
{
if(phead == NULL || BeDelete == NULL) return NULL;
ListNode *p=phead;
for(;p->pnext != NULL;p=p->pnext)
{
if(p->pnext == BeDelete)
{
return p;
}
}
return NULL;
}
5.单链表的删除
(1) O(n)的时间复杂度删除:
先从头遍历,在链表中找到待删除的节点i的前一个节点h,让h的pnext指向节点i的下一个节点j,然后删除这个节点i
void DeleteNode(ListNode *phead,ListNode* BeDelete)
{
if(phead == NULL || BeDelete == NULL) return ;
ListNode * p =SearchPrev(phead,BeDelete);//待删除节点的前驱
ListNode* q= BeDelete;//****要重新定义一个节点指向待删除的节点
p->pnext = q->pnext;//使待删除节点的前一个节点指向待删除节点的后一个节点
free(q);//删除
}
(2) O(1)的时间复杂度删除
把待删除节点的下一个节点的内容复制到待删除节点,然后把下一个节点删除,相当于把当前要删除的节点删除了
这个方法虽然时间复杂度小,但是要考虑的情况很多(3种):删除的是不是尾节点,这个尾节点会不会是头节点
void DeleteListNode(ListNode * phead,ListNode *BeDelete)
{
if(phead == NULL || BeDelete == NULL) return ;
if(BeDelete->pnext != NULL)//1.要删除节点的下一个节点不是尾节点,即不是空
{
ListNode *p = BeDelete->pnext;//p是待删除节点的下一个节点
BeDelete->mval = p->mval;
BeDelete->pnext = p->pnext;
delete p;
p = NULL;//删除后置空
}
else if(phead == BeDelete)//2.链表只有一个节点,既是头节点,也是尾节点
{
delete BeDelete;
phead = NULL;
BeDelete = NULL;//只有一个节点就还得把这个头节点置空****
}
else //链表中有多个节点,要删除的是尾节点
{
ListNode* p = phead;
for(;p->pnext != NULL;p=p->pnext)//让p走到链表尾的上一个节点处
{
if(p == BeDelete) break;
}
p->pnext = BeDelete->pnext;//BeDelete->pnext其实就是NULL
delete BeDelete;
BeDelete = NULL;
}
}
6.单链表的正序打印
void Show(ListNode *phead)
{
ListNode *p = phead->next;
for(;p != NULL;p=p->pnext)
{
cout<<p->mval<<" ";
}
cout<<endl;
}
7.(1)从尾到头打印链表,用栈
void PrintListReverse(ListNode *phead)//这个没有返回,直接打印
{
ListNode *p = phead;
stack<ListNode*> st;
while(p != NULL)//入栈
{
st.push(p);
p = p->pnext;
}
while(!st.empty())//出栈
{
p = st.top();
st.pop();
cout<<p->mval<<" ";
}
cout<<endl;
}
(2)从尾到头打印链表,用递归,缺点是容易导致栈溢出
vector<int> PrintListReverse_digui(ListNode *phead)//将_vec返回,在调用它的函数中进行打印
{
vector<int> _vec;
assert(phead != NULL);
if(phead->pnext != NULL)
{
PrintListReverse_digui(phead->pnext);
}
_vec.push_back(phead->mval);
return _vec;
}
8.链表的逆置
ListNode* ReverseList(ListNode* phead)//逆置之后没有改变头节点,依然可以返回,不返回也可以
{
if(phead == NULL) return NULL;
ListNode * p = phead->pnext;
phead->pnext = NULL;
ListNode* q = phead;
while(p != NULL)
{
q = p->pnext;
p->pnext = phead->pnext;
phead->pnext = p;
p = q;
}
return phead;
}