【面试】数据结构

来源:互联网 发布:天顶星人 知乎 编辑:程序博客网 时间:2024/05/22 05:25

单链表

先给出定义部分和相关调试部分

#include <bits/stdc++.h>using namespace std;struct ListNode{    int v;    struct ListNode *next;}*head;ListNode* insert(int v){    ListNode* p=head;    if(head == NULL)    {        head = new ListNode;        head -> next = 0;        head->v = v;        return head;    }    while(p->next!=NULL)        p = p->next;    p -> next = new ListNode;    p = p ->next;    p->next = NULL;    p -> v =v;    return p;}void show(){    for(ListNode*p = head;p!=NULL;p=p->next)        printf("%d ",p->v);    puts("");}

单链表翻转

通过三个指针实现.

ListNode*rev(ListNode *head){    ListNode *p,*q,*t;    ///保证最少有两个节点    if(head == NULL||head -> next == NULL)        return head;    p = NULL;    q = head;    t = head;    while(t!=NULL)    {        t = t -> next;        q->next = p;        p = q;        q = t;    }    return p;}

调试与验证

void showRev(){    head = NULL;    show();    head = rev(head);    show();    insert(1);    show();    head = rev(head);    show();    head = rev(head);    insert(2);    show();    head = rev(head);    show();    head = rev(head);    insert(3);    show();    head = rev(head);    show();    head = rev(head);    insert(4);    show();    head = rev(head);    show();    head = rev(head);}

判环

定义两个指针,一个一次走两个,另一个一次走一个. 如果有环就会相遇

bool hasLoop(ListNode *head){    ListNode *p1 , *p2;    p1 = p2 = head;    while(NULL != p1 && NULL != p1 ->next)    {        p1 = p1 -> next;        p1 = p1 -> next;        p2 = p2 -> next;        if(p1 == p2)            return 1;    }    return 0;}

调试与验证

void showHasLoop1(){    ListNode *a , *b;    head = NULL;    show();    printf("ans:%d\n",hasLoop(head));    show();    a = insert(1);    show();    printf("ans:%d\n",hasLoop(head));    show();    a -> next = head;    printf("ans:%d\n",hasLoop(head));}void showHasLoop2(){    head = NULL;    insert(1);    insert(2);    insert(3) -> next = head;    printf("ans:%d\n",hasLoop(head));}void showHasLoop3(){    ListNode *a;    head = NULL;    insert(1);    insert(2);    a = insert(3);    insert(4);    insert(5);    insert(6) -> next = a;    printf("ans:%d\n",hasLoop(head));}

环长

先判环,如果有环,那么就一个指针移动,另一个不动,作为标记.

int circleLen(ListNode *head){    ListNode *p1 , *p2;    p1 = p2 = head;    int cnt=0;    while(NULL != p1 && NULL != p1 ->next)    {        p1 = p1 -> next;        p1 = p1 -> next;        p2 = p2 -> next;        if(p1 == p2)        {            p1 = p1 -> next;            for(cnt = 1;p1 != p2;cnt ++)            {                p1 = p1 -> next;            }            break;        }    }    return cnt;}

验证

void showCircleLen1(){    ListNode *a , *b;    head = NULL;    show();    printf("ans:%d\n",circleLen(head));    show();    a = insert(1);    show();    printf("ans:%d\n",circleLen(head));    show();    a -> next = head;    printf("ans:%d\n",circleLen(head));}void showCircleLen2(){    head = NULL;    insert(1);    insert(2);    insert(3) -> next = head;    printf("ans:%d\n",circleLen(head));}void showCircleLen3(){    ListNode *a;    head = NULL;    insert(1);    insert(2);    a = insert(3);    insert(4);    insert(5);    insert(6) -> next = a;    printf("ans:%d\n",circleLen(head));}

环前链长

还是定义两个指针,p1指针先走环长个节点,然后p1和p2步进,再次相遇的时候p2走的步数就是链长.需要注意的是没有环的情况.

int linkLen(ListNode *head){    int ret;    int len = circleLen(head);    ListNode *p1, *p2 ;    p1 = p2 = head;    for(int i = len; i ; i-- )    {        p1 = p1 -> next;    }    for(ret = 0;p1 != p2 || (NULL != p1 && len == 0); ret++ )    {        p1 = p1 -> next;        p2 = p2 -> next;    }    return ret;}

验证

void showLinkLen1(){    ListNode *a , *b;    head = NULL;    show();    printf("ans:%d\n",linkLen(head));    show();    a = insert(1);    show();    printf("ans:%d\n",linkLen(head));    show();    a -> next = head;    printf("ans:%d\n",linkLen(head));}void showLinkLen2(){    head = NULL;    insert(1);    insert(2);    insert(3) -> next = head;    printf("ans:%d\n",linkLen(head));}void showLinkLen3(){    ListNode *a;    head = NULL;    insert(1);    insert(2);    a = insert(3);    insert(4);    insert(5);    insert(6) -> next = a;    printf("ans:%d\n",linkLen(head));}

全部代码

#include <bits/stdc++.h>using namespace std;struct ListNode{    int v;    struct ListNode *next;}*head;ListNode* insert(int v){    ListNode* p=head;    if(head == NULL)    {        head = new ListNode;        head -> next = 0;        head->v = v;        return head;    }    while(p->next!=NULL)        p = p->next;    p -> next = new ListNode;    p = p ->next;    p->next = NULL;    p -> v =v;    return p;}void show(){    for(ListNode*p = head;p!=NULL;p=p->next)        printf("%d ",p->v);    puts("");}ListNode*rev(ListNode *head){    ListNode *p,*q,*t;    ///保证最少有两个节点    if(head == NULL||head -> next == NULL)        return head;    p = NULL;    q = head;    t = head;    while(t!=NULL)    {        t = t -> next;        q->next = p;        p = q;        q = t;    }    return p;}void showRev(){    head = NULL;    show();    insert(1);    show();    head = rev(head);    show();    head = rev(head);    insert(2);    show();    head = rev(head);    show();    head = rev(head);    insert(3);    show();    head = rev(head);    show();    head = rev(head);    insert(4);    show();    head = rev(head);    show();    head = rev(head);}bool hasLoop(ListNode *head){    ListNode *p1 , *p2;    p1 = p2 = head;    while(NULL != p1 && NULL != p1 ->next)    {        p1 = p1 -> next;        p1 = p1 -> next;        p2 = p2 -> next;        if(p1 == p2)            return 1;    }    return 0;}void showHasLoop1(){    ListNode *a , *b;    head = NULL;    show();    printf("ans:%d\n",hasLoop(head));    show();    a = insert(1);    show();    printf("ans:%d\n",hasLoop(head));    show();    a -> next = head;    printf("ans:%d\n",hasLoop(head));}void showHasLoop2(){    head = NULL;    insert(1);    insert(2);    insert(3) -> next = head;    printf("ans:%d\n",hasLoop(head));}void showHasLoop3(){    ListNode *a;    head = NULL;    insert(1);    insert(2);    a = insert(3);    insert(4);    insert(5);    insert(6) -> next = a;    printf("ans:%d\n",hasLoop(head));}int circleLen(ListNode *head){    ListNode *p1 , *p2;    p1 = p2 = head;    int cnt=0;    while(NULL != p1 && NULL != p1 ->next)    {        p1 = p1 -> next;        p1 = p1 -> next;        p2 = p2 -> next;        if(p1 == p2)        {            p1 = p1 -> next;            for(cnt = 1;p1 != p2;cnt ++)            {                p1 = p1 -> next;            }            break;        }    }    return cnt;}void showCircleLen1(){    ListNode *a , *b;    head = NULL;    show();    printf("ans:%d\n",circleLen(head));    show();    a = insert(1);    show();    printf("ans:%d\n",circleLen(head));    show();    a -> next = head;    printf("ans:%d\n",circleLen(head));}void showCircleLen2(){    head = NULL;    insert(1);    insert(2);    insert(3) -> next = head;    printf("ans:%d\n",circleLen(head));}void showCircleLen3(){    ListNode *a;    head = NULL;    insert(1);    insert(2);    a = insert(3);    insert(4);    insert(5);    insert(6) -> next = a;    printf("ans:%d\n",circleLen(head));}int linkLen(ListNode *head){    int ret;    int len = circleLen(head);    ListNode *p1, *p2 ;    p1 = p2 = head;    for(int i = len; i ; i-- )    {        p1 = p1 -> next;    }    for(ret = 0;p1 != p2 || (NULL != p1 && len == 0); ret++ )    {        p1 = p1 -> next;        p2 = p2 -> next;    }    return ret;}void showLinkLen1(){    ListNode *a , *b;    head = NULL;    show();    printf("ans:%d\n",linkLen(head));    show();    a = insert(1);    show();    printf("ans:%d\n",linkLen(head));    show();    a -> next = head;    printf("ans:%d\n",linkLen(head));}void showLinkLen2(){    head = NULL;    insert(1);    insert(2);    insert(3) -> next = head;    printf("ans:%d\n",linkLen(head));}void showLinkLen3(){    ListNode *a;    head = NULL;    insert(1);    insert(2);    a = insert(3);    insert(4);    insert(5);    insert(6) -> next = a;    printf("ans:%d\n",linkLen(head));}int main(){    showLinkLen3();}

定义和性质:

  • 二叉堆是完全二叉树
  • 父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值
  • 每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)

(以下例子使用大根堆)

建立(维护)

  1. 按倒序扫一遍父节点
  2. 对于每个父节点找到最大的一个子节点,若该节点严格大于父节点,则交换父子的值,再对该节点递归的进行第二步,直到没有子节点大于父节点,此时继续执行第一步.

思考:当我们执行第 2 步的时候,我们就是在维护这个子堆的性质.假如 子堆A 满足性质,那么这个 子堆A 的 父节点B 一定能在少于 logn 次交换后,使子堆 A∪B 满足堆的性质.

插入

把要插入的数当成堆的最后一个元素,要维护堆把该节点与父节点进行交换,递归执行,直到满足堆的性质(该节点严格小于父节点)

删除

大根堆规定只能删除最大元素,也就是头结点.步骤如下:

  1. 移除头结点
  2. 将最后一个节点换到头部(代码中是 1,2 步结合,将头结点与最后一个节点置换,然后长度 -1 )
  3. 执行建立时第 2 步操作,维护堆的性质

排序

利用大根堆的性质,每次可以删除最大的元素,我们把这个元素放在队列最后不去考虑他,递归执行找第 n-i 大的元素放在队列尾部.这样就形成了一个非递减数列.

代码

#include <bits/stdc++.h>using namespace std;const int MAXN = 1e5;///BigRootstruct heap{    int A[MAXN] , n;    void init(int _n , int m)    {        n = _n;        srand(time(NULL));        for(int i=0;i<n;i++)            A[i] = rand() % m;    }    void show()    {        for(int i=0;i<n;i++)            printf("%d ",A[i]);        puts("");    }    int getLs(int num)    {        return ( ( num + 1 ) << 1 ) - 1;    }    int getRs(int num)    {        return ( num + 1 ) << 1 ;    }    int getF(int num)    {        return ( num - 1 ) >> 1;    }    void _fixDown(int num)    {        while(num<n)        {            int ls = getLs(num) , rs = getRs(num);            printf("\t%d %d\n",ls,rs);            int m ;            if (ls >= n)                break;            else if ( rs >= n)                m = ls;            else                m = ( A[ls] < A[rs] ? rs : ls );            if( A[num] < A[m] )            {                printf("\tswap(%d,%d)\n",num,m);                swap(A[num],A[m]);                num = m;            }            else                break;        }    }    void build()    {        for(int i = getF(n) ; i >= 0 ; i-- )            printf("B:%d\n",i),            _fixDown(i);    }    void insert(int v)    {        int num = n;        A[n++] = v;        int f;        while(num && A[num] > A[ f = getF(num) ] )        {            printf("\tswap(%d,%d)\n",num,f);            swap(A[num] , A[f]);            num = f;        }    }    void remove()    {        n--;        printf("\tswap(%d,%d)\n",n,0);        swap( A[n] , A[0] );        _fixDown(0);    }    void sort()    {        int _n = n;        build();        while(n)            remove();        n = _n;    }}h;char hit[10000];int offset = 0;void pt(char *s){    sprintf(hit+offset,s);    offset += strlen(s);}int AT[] = {2,1,6,1,2,2,6,2,8,5};int main(){    pt("i v\tinsert(v)\n");    pt("r\tremove()\n");    pt("p\tprint()\n");    pt("s\tsort()\n");    pt("h\thelp()\n");    h.init(10,10);    memcpy(h.A,AT,sizeof(AT));    h.show();    h.build();    h.show();    char op[5];    while(scanf("%s",op)!= EOF)    {        int v;        switch (op[0])        {        case 'i':            scanf("%d",&v);            h.insert(v);            break;        case 'r':            h.remove();            break;        case 'p':            h.show();            break;        case 's':            h.sort();            break;        case 'h':            puts(hit);            break;        case 'q':            return 0;        }    }    return 0;}
1 0
原创粉丝点击