链表的算法面试题总结

1、单链表的创建和遍历
 2、求单链表中节点的个数(太简单,就不写了)
 3、查找单链表中的倒数第k个结点(剑指offer,题15)
 4、查找单链表中的中间结点
 5、合并两个有序的单链表,合并之后的链表依然有序【出现频率高】(剑指offer,题17)
 6、单链表的反转【出现频率最高】(剑指offer,题16)
 7、从尾到头打印单链表(剑指offer,题5)
 8、判断单链表是否有环
 9、取出有环链表中,环的长度
 10、单链表中,取出环的起始点(剑指offer,题56)。本题需利用上面的第8题和第9题。
 11、判断两个单链表相交的第一个交点(剑指offer,题37)

完整代码(一)

#include <stdio.h>
#include <stdlib.h>
typedef char ElemType;

/* 1,创建链表,初始化,遍历 3,找到倒数第k个节点。 4,找到中间节点。 6,逆置要求空间复杂度o(1),时间复杂度o(n) */
/*
    创建链表:创建链表增删
*/
/**
    链表节点
*/
typedef struct knode{
    ElemType data;
    struct knode *next;
//  struct knode *prior;
}linknode;

// 创建头结点

linknode *create(){
    linknode *root;
    root = (linknode *)malloc(sizeof(linknode));
    root->next = NULL;
//  root->prior = NULL;
    return root;
}

// 从头部开始添加节点

void insert(linknode *s,int i) {
    linknode *p;
    while(i != 0) {
        p = (linknode *)malloc(sizeof(linknode));
        p->next = s->next;
//      p->prior = s;
        s->next =p;
//      printf("输入插入的数据:");
        scanf("%c",&p->data);               // 前面不能有其他输入流
        i--;
    }
}

// 遍历节点,并且返回节点长度。
int ergodic(linknode *s){
    int length = 0;
    s = s->next;
    if(s == NULL) return length;
    while(s){
        printf("%c ",s->data);
        s = s->next;
        length++;
    }
    return length;
}
// 长度
int length(linknode *s){
    int len = 0;
    s = s->next;
    if(s == NULL) return len;
    while(s){
        s = s->next;
        len++;
    }
    return len;
}

// 2.1)单链表,找到倒数第k个节点。并且输出。
int find(linknode *s,int k){
    int len,t;
    len = length(s);
    s = s->next;
    if(s == NULL) return 0;
    if(len < k) return 0;
    t = len - k;
    while(t-1 != 0){
        s = s->next;
        t--;
    }
    s = s->next;
    printf("第k个元素是%c\n",s->data);
    return 1;
}

/*
    2.2)链表找到倒数第k个节点。
*/

int finds(linknode *s,int k){
    linknode *q,*p;
    q=p=s;
    if(s == NULL) return 0;
    while(q != NULL && (k-1) != 0){     //  q 到顺数第k个节点。
        q = q->next;
        k--;
        return 0;
    }
    while(q->next != NULL && p != NULL){    // q->next如果为空,就表示结束向前移动。
        q = q->next;
        p = p->next;
    }
    printf("中间的节点:%c\n",p->data);
    return 1;
}


// 输出链表中间节点。
void middle(linknode *s){
    int len,t;
    len = length(s);
    if(len % 2 == 1){
        t = len/2 +1;
    }else{
        t = len/2;
    }
    while(t != 0){
        s = s->next;
        t--;
    }
    printf("这是中间的节点%c\n",s->data);
}

// 链表逆置,空间O(1)
/*

*/
linknode *reverse(linknode *s){
    linknode *head,*p,*r,*d;
    d = r = head = s;       
    s = head->next;         // s 指向第一个节点。
    while(s != NULL) {
        p = s->next;     // 让p指向s的下一个节点。    
        s->next = head;  // s 节点逆指向。
        head = s;       // head 节点向前移动。
        s = p;          // s节点向前移动,最后结果 s = NULL, p = NULL
    }
    d = r->next;        // d 就是为了找到最后一个节点。让它的next = NULL。r->next和最后一个节点在此时是双向的。
    d->next = NULL;     // 尾节点next为NULL 
    r->next = head;
    return r;
}

// 合并两个有序链表,非递归方法。


void main(){
    linknode *s,*r;
    s = create();
    // 插入
    int i,length;
    printf("插入节点的个数:");
    scanf("%d",&i);
    insert(s,i);
    //遍历
    length = ergodic(s);
    printf("链表的长度%d\n",length);
    find(s,3);
    //输出中间节点
    middle(s);
    //查倒数第k个节点
    finds(s,3);
    //逆置
    r = reverse(s);
    ergodic(r);

    printf("\n");
}

完整代码(二)

/** 5, 链表的合并。 7,(在不改变链表结构的前提下)逆序输出单链表的值 */
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
typedef char ElemType;

typedef struct node{
    ElemType data;
    struct node *next;
}linknode;


// 创建链表
linknode *create(){
    linknode *root;
    root = (linknode *)malloc(sizeof(linknode));
    root->next = NULL;
    root->data = NULL;
    return root;
}

// 初始化链表
void init(linknode *s,int k){
    linknode *p;
    cout<<"输入有序的字符串:";
    for(int i = 0; i < k; i++){
        p = create();
        cin>>p->data;
        s->next = p;
        s = p;
    }
}
// 遍历,带头结点的。
void pt(linknode *s){
    cout<<"输出内容:";
    s = s->next;
    while(s){
        cout<<s->data;
        s = s->next;
    }
    cout<<endl;
}
// 遍历不带头结点的。
void pts(linknode *s){
    cout<<"输出内容:";
    while(s){
        cout<<s->data;
        s = s->next;
    }
    cout<<endl;
}

//merge 合并有序链表(有序)(带头结点的)
linknode *merge(linknode *s,linknode *r){
    linknode *p,*p1,*p2,*root;
    // 两个链表都非空
    if(s->next == NULL) {
        return r;
    }
    if(r->next == NULL) {
        return s;
    }
    p1 = s->next;
    p2 = r->next;
    // 确定那个链表,成为新的链表头
    if(p1->data <= p2->data){
        root = p1;
        p = p1;             // p指向新选出的节点。
        p1 = p1->next;
    }else{
        root = p2;
        p = p2;
        p2 = p2->next;
    }
    //合并
    while(p1 != NULL && p2 != NULL) {
        if(p1->data <= p2->data) {
            p->next = p1;
            p1 = p1->next;
        }else{
            p->next = p2;
            p2 = p2->next;
        }
        p = p->next;
    }
    //如果有一个链表为空
    if(p1){
        p->next = p1;
    }
    if(p2){
        p->next = p2;
    }
    return root;
}

// (在不改变链表结构的前提下)逆序输出单链表的值

void outputs(linknode *s){
    if(s != NULL){          // 递归基
        if(s->next != NULL){
            outputs(s->next);
        }
    }
    cout<<s->data;      // 平凡事务 
}


void main(){
    linknode *s,*r,*h;
    int k;
    // 创建连接并且输出。
    cout<<"输入链表长度:";
    cin>>k;
    s = create();
    init(s,k);
    // 创建链表并且输出
    cout<<"输入链表长度:";
    cin>>k;
    r = create();
    init(r,k);
    //输出
    pt(s);
    pt(r);
    //合并
    h = merge(s,r);
    pts(h);
    // 逆输出h
    cout<<"非结构改变逆输出:";
    outputs(h);
    cout<<endl;
}   

    原文作者:jkCode
    原文地址: https://blog.csdn.net/newVenues/article/details/78768042
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞