【面试】数据结构

单链表

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

#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;

///BigRoot
struct 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值