单链表相关面试笔试题

1.链表节点结构定义

struct node {
node * next ;
int val ;
node(int x):val(x),next(NULL){}
};

/**
    从数组中构造单项链表
**/
node * construct_list(int a[] ,int n){
    node * head=NULL;
    node * p=NULL;
    node * q=NULL;
    for(int i=0;i<n;++i){
        p= new node(a[i]);
        if(q!=NULL)
            q->next=p;
        if(i==0){
            head=p;
        };
        q=p;
        p=p->next;
    }
    return head;
}

/**
    顺序输出单链表
**/
void output(struct node * head){
    if(head == NULL){
        cout<<"empty list !\n";
        return ;
    }
    node * p = head;
    while(p!= NULL){
        cout<<p->val<<" ";
        p=p->next;
    }
    cout<<"\n";
}

2.链表的逆序输出以及链表的逆序操作

/**
    逆序输出单链表,递归
**/

void reverse_output(struct node * head){
    if(head == NULL){
        return ;
    }else {
        node * p = head;
        reverse_output(p->next);
        cout<<p->val<<" ";
    }
}

/**
    逆转单链表
    思路:将node 一个个从链表中卸下来,然后逆序重组
**/

node *  reverse_list(node * head){
    if (head ==NULL ||head->next==NULL)return head;
    node * p=NULL, *q=NULL,*t=NULL;
    p=head;
    q=head->next;
    p->next=NULL;
    while(q){
        t=q;
        q=q->next;
        t->next=p;
        p=t;
    }
    return p;

}
//感觉这样可以少一个变量,但是不是很容易理解,主要是我们需要改变指针的值
void reverse_list1(node * *head){
    if (*head ==NULL ||(*head)->next==NULL)return ;
    node *q=NULL,*t=NULL;
    q=(*head)->next;
    (*head)->next=NULL;
    while(q){
        t=q;
        q=q->next;
        t->next=(*head);
        (*head)=t;
    }
}

3.判断链表中是否有环,有的话找出环的入口

/*
    判断链表是否有环,如果有的话,找出环的入口
    找环的入口2(x+y)=nr +(x+y) --> x=nr-y :其中x为开始到入口的步长,y为入口到首次相遇的步长
    r为环的长度
*/

bool has_cicle(node * head){
    bool has_cicle = false;
    if(head == NULL || head->next == NULL )return has_cicle;
    node * slow = head ,*fast = head ;//同一个起跑线
    while(true){
        slow = slow->next;
        fast = fast->next;
        if(fast) fast = fast->next;
        if(slow==NULL||fast==NULL)break;
        if(slow==fast){
            has_cicle=true;
            break;
        }
    }
    if(has_cicle==true){//找到环的入口
        node * start = head ;
        node * encounter = slow;
        while(start!=slow){
            start=start->next;
            slow=slow->next;
        }
        cout<<"entry point :"<<start->val<<" \n" ;
    }

    return has_cicle;

}

4.链表中的倒数第K个数

/**
    找到单链表中的倒数第K个元素问题,只给出单链表的头指针
    也是利用快慢两个指针,first指针首先走k步之后
    如果再次之前first已经走完了那么就说明没有找到这样的值
    否则,first 和second指针开始一起走,等到first指针走到最后,
    second 指针恰好走到了倒数第k个元素
**/

node * find_post_k_element(node * head,int k){
    node * first = head ;
    node * second =NULL;

    while(first!=NULL&&k>0){
        k--;
        first=first->next;
    }
    if(k>0)
        return NULL;
    else{
        second= head;
        while (first){//当first在第k+1个元素的时候 second元素在第1个元素,相隔正好是k个元素
            first=first->next;
            second=second->next;
        }
    }

    return second;
}

5.求链表中间的元素

/**
    找出链表的中间元素
    好吧,还是两个指针吧,步长两倍关系即可
**/
node * find_mid_element(node * head){
    if(head==NULL||head->next == NULL){
        return head;
    }
    node * single = head;
    node * double_step = head;
    while(double_step){
        double_step=double_step->next;
        if(double_step)
            double_step=double_step->next;
        if(double_step)
            single=single->next;//注意指针走动的顺序
    }
    return single;
}

6.有序链表的合并问题,包括递归和非递归的实现

/**
    两个升序链表的合并问题,非递归
**/

node * merge_lists(node * head1 ,node * head2){
    if(head1 == NULL)return head2;
    if(head2 == NULL)return head1;
    node * head = NULL;
    node * temp = NULL;
    while(true){
        while(head1&&head2&&head1->val<=head2->val){//head1 head 2都得判断是否为空
            if(temp == NULL){
                temp = head1;
                head = temp;
            }
            else{
                temp->next = head1;
                temp = temp->next;//指针要走动的
            }
            head1 = head1->next;
        }

        while(head2&&head1&&head2->val<=head1->val){
            if(temp == NULL) {
                temp = head2 ;
                head= temp;
            }else{
                temp ->next = head2;
                temp=temp->next;
            }
            head2 = head2->next;
        }

        if(head1 == NULL){
            while(head2){
                temp ->next = head2;
                temp=temp->next;
                head2 = head2->next;
            }
            break;
        }
        if(head2 == NULL){
            while(head1){
                temp ->next = head1;
                head1 = head2->next;
                temp=temp->next;
            }
            break;
        }
        if(head1==NULL&&head2==NULL)break;
    }
    return head;
}
//递归版本
node * merge_lists1(node * head1 , node * head2){
    node * head = NULL;
    if(head1 == NULL)return head2;
    if(head2 == NULL)return head1;

    if(head1->val<=head2->val){
        head = head1;
        head ->next = merge_lists1(head1->next,head2);
    }else{
        head = head2 ;
        head ->next = merge_lists1(head1,head2->next);
    }
    return head;

}

7.删除单链表中的重复数据,链表无序

常见的这个题目分为两个要求,一是在空间复杂度O(1),另一个则是木有限制,一般而言空间有限制的情况下只能通过暴力的遍历解决了,但是如果没什么限制的话使用hash表来帮助操作是比较省时的,时间复杂度为O(n),貌似C++11中才有的hash表可以用,代码如下:
/**
    未排序的链表中的重复值的删除
    1.不限制空间复杂度
    2.空间复杂度在O(1)的实现
**/

//复杂度 O(n*n)
void remove_duplicate1(node * head){
    if(head==NULL||head->next==NULL)return;
    node * first =head,*second =NULL,* t = NULL;
    while(first){
        second=first->next;
        t=first;
        while(second){
            if(second->val==first->val){
                t->next=second->next;
                delete second;
                second=t->next;
            }else{
                t=second;
                second=second->next;
            }
        }
        first=first->next;
    }
}


void remove_duplicate2(node * head){
    if(head==NULL||head->next==NULL)return;
    hash<int>h;
    h(head->val)=true;
    node * p = head->next,*q=head;
    while(p){
        if(h(p->val)==true){
            q->next=p->next;
            delete p;
            p=q->next;
        }else{
            h(p->val)=true;
            q=p;
            p=p->next;
        }
    }
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值