</pre>链表涉及到大量的指针操作,实际写代码时,很容易出错。本文对常见的一些链表操作进行整理。<pre name="code" class="cpp">#include <iostream>
#include<vector>
#include<stdlib.h>
#include<stack>
using namespace std;
//****************************************//
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
ListNode* creatlist(vector<int> a,int n);
ListNode* creatnode(int val);
void Fprint_linklist(ListNode *head);//从头到尾打印链表
void Bprint_linklist(ListNode *head);//从尾到头打印链表
void delete_exit_node(ListNode **head,ListNode* node);//删除链表中某个存在的节点,要求时间复杂度为O(1)
void delete_val(ListNode **head,int val);//删除链表中数据值等于给定值的节点
ListNode* get_bkth_node(ListNode *head,int k);//获得链表中的倒数第K个节点
ListNode* reverse_linklist(ListNode **head);//反转链表,返回值反转以后链表的头结点
ListNode* first_common_node(ListNode* head1,ListNode* head2);//寻找链表的第一个公共节点,并返回公共节点
//寻找两个链表的第一个公共点
int main()
{
const int num1=8;
const int num2=10;
vector<int> A(num1);
vector<int> B(num2);
srand(1);
for(int i=2;i<num1;i++){
A[i]=rand()%100;
}
for(int i=2;i<num2;i++){
B[i]=rand()%200;
}
//********创建链表测试********//
ListNode* head1=creatlist(A,num1);
ListNode* head2=creatlist(B,num2);
ListNode* node1=head1;
ListNode* node2=head2;
ListNode* comm_node=new ListNode(88);
while(node1->next!=NULL)
node1=node1->next;
while(node2->next!=NULL)
node2=node2->next;
node1->next=comm_node;
node2->next=comm_node;
cout<<"正向打印链表1: "<<endl;
Fprint_linklist(head1);//正向打印链表
cout<<endl;
cout<<"正向打印链表2: "<<endl;
Fprint_linklist(head2);//正向打印链表
cout<<endl;
cout<<"反向打印单链表1:";
Bprint_linklist(head1);//反向打印链表
cout<<endl;
cout<<"寻找两个链表的第一个公共节点: "<<endl;
ListNode* p=first_common_node(head1,head2);
cout<<"第一个公共节点的值为: "<<p->val<<endl;
cout<<endl;
cout<<"反转链表"<<endl;
head1=reverse_linklist(&head1);//反转链表
Fprint_linklist(head1);
cout<<endl;
cout<<"取得倒数第k个节点测试: ";
cout<<endl;
ListNode *knode=get_bkth_node(head1,2);
cout<<"第k个节点的值为:"<<knode->val<<endl;
cout<<endl;
cout<<"测试删除某个固定的节点: ";
ListNode* node_delete=head1;
delete_exit_node(&head1,node_delete);
Fprint_linklist(head1);
cout<<endl;
cout<<"测试删除等于固定值的节点:";
delete_val(&head1,41);
Fprint_linklist(head1);
}
//函数功能:采用头插法创建链表
ListNode* creatlist(vector<int> a,int n){
if(a.size()==0||n<=0)
return NULL;
ListNode *head=NULL;
for(int i=0;i<n;i++){
ListNode *node=creatnode(a[i]);
if(head==NULL){
head=node;
}
else{
node->next=head;
head=node;
}
}
return head;
}
//函数功能:创建节点
ListNode* creatnode(int val){
ListNode *p=new ListNode(val);
return p;
}
//函数功能:从头到尾打印链表
void Fprint_linklist(ListNode *head){
if(head==NULL)
return ;
ListNode *p=head;
while(p){
cout<<p->val<<" ";
p=p->next;
}
cout<<endl;
}
/*函数功能:从尾到头反向打印链表
时间复杂度为:o(n)
空间复杂度为:o(n),使用了一个栈做为存储空间
*/
void Bprint_linklist(ListNode *head){
if(head==NULL)
return ;
stack<ListNode*> temp;
ListNode *node=head;
while(node!=NULL){
temp.push(node);
node=node->next;
}
while(!temp.empty()){
ListNode *m=temp.top();
temp.pop();
cout<<m->val<<" ";
}
cout<<endl;
}
/*函数功能:删除链表中某个存在的节点,要求时间复杂度为O(1)
算法思想:通过拷贝要删除节点的后继节点的数据,然后删除后继节点即可,考虑特殊节点:尾节点处理*/
void delete_exit_node(ListNode **head,ListNode* node){
if(head==NULL||*head==NULL||node==NULL)
return ;
//要删除的节点不是尾节点
if(node->next!=NULL){
ListNode *q=node->next;
node->val=node->next->val;
node->next=q->next;
delete q;
q=NULL;
}
//链表中只有头结点
else if(*head==node){
delete node;
node=NULL;
*head=NULL;
}
//对于尾节点的处理还是不太明白;
else {
ListNode *p=*head;
while(p->next!=node)
p=p->next;
p->next=node->next;
delete node;
node=NULL;
}
}
/*函数功能:删除链表中等于某个值得节点
思路:需要先判断要删除的节点是否在链表中;
若在则将值等于给定值得节点全部删除;
否则删除失败
*/
void delete_val(ListNode **head,int val){
if(head==NULL||*head==NULL){
cout<<"链表中不存在值等于"<<val<<"的节点"<<endl;
return ;
}
ListNode *pre=NULL;
ListNode *curr=*head;
ListNode *pnext=curr->next;
int flag=0;
while(curr!=NULL){
if(curr->val==val){
//要删除的是头结点
if(curr==*head){
*head=pnext;
delete curr;
}
else{
pre->next=pnext;
delete curr;
}
flag=1;//用于标识链表中是否存在等于给定值的节点
curr=pnext;
if(curr==NULL)
break;
pnext=pnext->next;
}
else{
pre=curr;
curr=pnext;
if(curr==NULL)
break;
pnext=pnext->next;
}
}
if(flag==0)
cout<<"链表中不存在值等于"<<val<<"的节点 ";
else
cout<<"删除节点值为"<<val<<"的节点 ";
}
/*函数功能:删除链表中倒数第k的节点
思想:设置两个指针,均指向头结点,让一个指针先走k步,然后另外一个指针开始移动,直到第一个指针到达链表的结尾
假设链表总长为n,第二个指针实际上走了n-k步,即指向倒数第k个节点*/
ListNode* get_bkth_node(ListNode *head,int k){
if(head==NULL)
return NULL;
ListNode *node1=head;
ListNode *node2=head;
for(int i=0;i<k;i++){
node1=node1->next;
if(node1==NULL)//如果链表本身的长度就小于k
return NULL;
}
while(node1!=NULL){
node1=node1->next;
node2=node2->next;
}
return node2;
}
/*函数功能:反转链表*/
ListNode* reverse_linklist(ListNode **head){
if(head==NULL||*head==NULL)
return NULL;
if((*head)->next==NULL)
return *head;
ListNode *pre=NULL;
ListNode *curr=*head;
ListNode *pnext=curr->next;
while(curr!=NULL){
curr->next=pre;
*head=curr;
pre=curr;
curr=pnext;
if(curr==NULL)
break;
pnext=pnext->next;
}
return *head;
}
/*函数功能:寻找两个链表的第一个公共节点*/
ListNode* first_common_node(ListNode* head1,ListNode* head2){
if(head1==NULL||head2==NULL)
return NULL;
int len1=0,len2=0;
ListNode *node1=head1;
ListNode *node2=head2;
while(node1!=NULL){
++len1;
node1=node1->next;
}
while(node2!=NULL){
++len2;
node2=node2->next;
}
int dvalue=len1-len2;
ListNode *temp=NULL;
ListNode *node=NULL;
if(dvalue>=0){
temp=head1;
node=head2;
}
else{
dvalue=len2-len1;
temp=head2;
node=head1;
}
while(dvalue){
temp=temp->next;
--dvalue;
}
while(temp!=NULL){
if(temp==node)
return node;
temp=temp->next;
node=node->next;
}
cout<<"两个链表不存在公共节点"<<endl;
return NULL;
}
代码运行结果: