数据结构和算法

    数据结构和算法

    单链表

    struct Node
    {
        int data;
        Node *nextNode;
    };
    

    创建列表

    Node *CreatList()
    {
        Node *head,*p,*s;
        int cycle=1,x;
        int count=0;
        head=(Node*)malloc(sizeof(Node));
        p=head;
    
        while(cycle)
        {
            s=(Node*)malloc(sizeof(Node));
            printf("Input value:\n");
            scanf("%d",&x);
            if (0==x)
            {
                break;
            }
            else
            {
                s->data=x;
                p->nextNode=s;
                p=s;
                count++;
            }
    
        }
        p->nextNode=NULL;
        head->data=count;
        return head;
    }
    

    链表删除

    Node* DeleteNode(Node*Head,int value)
    {
        Node* p1,*p2;
        p1=Head;
    
        while(value!=p1->data && p1->nextNode!=NULL)
        {
            p2=p1;
            p1=p1->nextNode;
        }
        if (value==p1->data)
        {
            if (p1==Head)
            {
                Head=p1->nextNode;
                free(p1);
            }
            else
            {
                p2->nextNode=p1->nextNode;
            }
        }
    
         return Head;
    }
    

    链表插入

    Node* InsertNode(Node* Head,int index,int value)
    {
        Node *p1,*p2,*s;
        int count=1;
        p1=Head;
    
        s=(Node*)malloc(sizeof(Node));
        s->data=value;
        while (count<index && p1->nextNode!=NULL)
        {
            p2=p1;
            p1=p1->nextNode;
            count++;
        }
        if (count==index && p1->nextNode!=NULL)
        {
            if (Head==p1)
            {
                s->nextNode=p1;
                Head=s;
            }
            else
            {
                p2->nextNode=s;
                s->nextNode=p1;
    
            }
    
        }
        if (count==index && p1->nextNode==NULL)
        {
            p1->nextNode=s;
            s->nextNode=NULL;
        }
    
        return Head;
    
    }
    

    链表逆置

    Node* Reverse(Node *Head)
    {
        Node *p1,*p2,*p3;
    
        if (Head==NULL && Head->nextNode==NULL)
        {
            return Head;
        }
        p1=Head;
        p2=p1->nextNode;        
        while(p2!=NULL)
        {
    
            p3=p2->nextNode;
            p2->nextNode=p1;
            p1=p2;
            p2=p3;
        }
    
        Head->nextNode=NULL;
        Head=p1;
        return Head;
    }
    

    队列(先进先出FIFO)

    typedef struct linkqueue
    {
        Node *front,*rear;
    }queue;
    

    入队

    queue *insert(queue *HQ,int val)
    {
        Node *s;
        s=(Node*)malloc(sizeof(Node));
        s->data=val;
        s->nextNode=NULL;
        if (HQ->rear==NULL)
        {
            HQ->front=s;
            HQ->rear=s;
        }
        else
        {
            HQ->rear->nextNode=s;
            HQ->rear=s;
        }
        return HQ;
    }
    

    出队

    queue *del(queue *HQ)
    {
        Node *p;
        if (HQ->front!=NULL)
        {
            p=HQ->front;
            if (HQ->front==HQ->rear)
            {
                HQ->front=NULL;
                HQ->rear=NULL;
            }
            else
            {
                HQ->front=HQ->front->nextNode;
                free(p);
            }
        }
        return HQ;  
    }
    

    排序

    快速排序

    基本思想:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

    int Partition(int arr[],int low,int high)
    {
        int pivotKey=arr[low];
    
        while(low<high)
        {
            while (low<high && arr[high]>=pivotKey)
            {
                high--;
            }
    
            swap(arr[low],arr[high]);
    
            while (low<high  && arr[low]<=pivotKey)
            {
                low++;
            }
    
            swap(arr[low],arr[high]);
    
        }
        return low;
    }
    
    void QSort(int arr[],int low,int high)
    {
        int pivot=0;
        if(low<high)
        {
            pivot=Partition(arr,low,high);
            QSort(arr,low,pivot-1);
            QSort(arr,pivot+1,high);
        }
    }
    

    选择排序

    基本思想:每一趟在n-i+1个记录中选取关键字最小的记录作为有序序列的第i个记录。它最大的特点就是交换移动数据次数相当少。

    void SelectSort(int arr[],int len)
    {
        int min=0;
    
        for (int i=0;i<len-1;i++)
        {
            min=i;
            for (int j=i+1;j<len;j++)
            {
                if (arr[j]<arr[min])
                {
                    min=j;
                }
            }
            if (min!=i)
            {
                swap(arr[min],arr[i]);
            }
        }
    }
    

    插入排序

    void InsertSort(int a[],int len)
    {
        int i,j;
        for (i=1;i<len;i++)
        {
            if (a[i]<a[i-1])
            {
                int temp=a[i];
                for(j=i-1;j>=0 && a[j]>temp;j--)
                {
                    a[j+1]=a[j];
                }
                a[j+1]=temp;
            }
    
        }
    }
    

    堆排序

    void HeapAdjust(int a[],int len)
    {
        int temp;
        int childIndex;
        int count=(len-1)/2;
        for (int i=count;i>=0;i--)
        {
            temp=a[i];
            childIndex=2*i+1;
    
            if (childIndex<len && a[childIndex]<a[childIndex+1])
            {
                childIndex++;
            }
            if (temp<a[childIndex])
            {
                swap(a[i],a[childIndex]);
            }
        }
    }
    
    void HeapSort(int a[],int len)
    {
        for(int i=len-1;i>0;i--)
        {
            HeapAdjust(a,i);
            swap(a[0],a[i]);
        }
    }
    

    归并排序

    归并排序是分治法的一个非常典型的应用,且各层分治递归可以同时进行。其核心思想是将两个有序的数列合并成一个大的有序的序列,通过递归,层层合并,即为归并。

    字符串

    整数转为字符串

    整数加‘0’隐形转化为char类型的数

    void itoa(int n,char s[])
    {
        char temp[11];
        int index=0;
        int sign=0;
        int j=0;
        if (n<0)
        {
            n=-n;
            sign=-1;
        }
        while(n&&index<=10)
        {
            temp[index++]=n%10+'0';
            n=n/10;
        }
        temp[index]=NULL;
        index=index-1;
    
        if (sign<0)
        {
            s[j]='-';
            j++;
        }
        while (index>=0)
        {
            s[j]=temp[index];
            index--;
            j++;
        }
        s[j]=NULL;
    }
    

    字符串转为整数

    int atoi(char s[])
    {
        int i=0;
        int sum=0;
        int sign=1;
        if (s[i]=='-')
        {
            sign=-1;
            i++;
        }
        while(s[i]!=NULL)
        {
            if ((s[i]<'0')||(s[i]>'9'))
            {
                break;
            }
            sum=sum*10+(s[i]-'0');
            i++;
        }
        sum=sign*sum;
        return sum;
    }
    

    strcpy

    char *strcpy(char *destStr,char *srcStr)
    {
        char *address;
        address=destStr;
        if (destStr==NULL && srcStr==NULL)
        {
            return NULL;
        }
        while((*destStr++=*srcStr++)!='\0')
            NULL;
        return address;
    }
    

    strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?

    答:为了实现链式表达式。

    例如 int length = strlen( strcpy( strDest, “hello world”) );

    串拷贝(strcpy)和内存拷贝(memcpy)有什么不同?它们适合于在哪种情况下使用?

    strcpy()函数只能拷贝字符串,将源字符串的每个字节拷贝到目的字符串中。当遇到字符串末尾的NULL字符(\0)时,他会删除该字符,并结束拷贝。

    memcpy()函数可以拷贝任意类型的数据。因为并不是所有的数据都是以NULL字符结束,所以要为memcpy()函数指定要拷贝的字节数。

    在拷贝字符串时,通常使用strcpy()函数,在拷贝其他数据(如结构)时,通常使用memcpy()

    memcpy

    void *memcpy(char *dest,char *src,size_t size)
    {
        if (dest==NULL && src==NULL)
        {
            return NULL;
        }
        char *tempSrc=src;//防止改变src
        char *tempDest=dest;
        while(size-->0)
            *tempDest++=*tempSrc++;
        return dest;
    }
    

    计算字符串中单词数量

    int CountWords(char *str)
    {
        int count=0;
        int flag=0;
        if (str==NULL)
        {
            return count;
        }
        else
        {
            while(*str!=NULL)
            {
                if (*str==' ')
                {
                    flag=0;
                }
                else if(flag==0)
                {
                    flag=1;
                    count++;
                }
                str++;
            }
        }
        return count;
    }
    

    字符串逆序

    char* ReverseStr(char *str)
    {
        char *p,*q;
        p=str;
        q=str;
        while(*q)
        {
            q++;
        }
        q--;
        while (q>p)
        {
            char t=*p;
            *p++=*q;
            *q--=t;
        }
    
        return str;
    }
    

    按单词逆序

    思路:按单词逆序,然后将整个句子作为整体之后再逆序一次

    void ReverseWord(char *p,char *q)
    {
        while(p<q)
        {
            char t;
            t=*p;
            *p++=*q;
            *q--=t;
        }
    }
    
    char* Reverse(char*str)
    {
        char *p;
        char *q;
        p=str;
        q=str;
        while(*q!=NULL)
        {
            if (*q==' ')
            {
                ReverseWord(p,q-1);
                q++;
                p=q;
            }
            else
                q++;
        }
        ReverseWord(p,q-1);
        ReverseWord(str,q-1);
        return str;
    }
    

    二叉树

    创建树

    void CreateTree(BiTree *tree,int value)
    {   
        if (*tree==NULL)
        {
            BiTree node=(BiTNode*)malloc(sizeof(BiTNode));
            node->data=value;
            node->lChild=NULL;
            node->rChild=NULL;
            *tree=node;
            return;
        }
        else if (value<(*tree)->data)
        {
            CreateTree(&(*tree)->lChild,value);
        }
        else if (value>(*tree)->data)
        {
            CreateTree(&(*tree)->rChild,value);
        }
        else
        {
    
    
        }
    }
    

    遍历树

    /*前序遍历*/
    void PreOrderTraverse(BiTree T)
    {
        if (T==NULL)
        {
            return;
        }
        else
        {
            int data;
            data=T->data;
            cout<<data<<endl;
            PreOrderTraverse(T->lChild);
            PreOrderTraverse(T->rChild);
        }
    }
    
    /*中序遍历*/
    void InOrderTraverse(BiTree T)
    {
        if (T==NULL)
        {
            return;
        }
        else
        {
            int data;
            data=T->data;       
            InOrderTraverse(T->lChild);
            cout<<data<<endl;
            InOrderTraverse(T->rChild);
        }
    }
    
    /*后序遍历*/
    void PostOrderTraverse(BiTree T)
    {
        if (T==NULL)
        {
            return;
        }
        else
        {
            char data;
            data=T->data;       
            PostOrderTraverse(T->lChild);
            PostOrderTraverse(T->rChild);
            cout<<data<<endl;
        }
    }
    

    已知前序、中序求后序

    void initTree(BiTree *root,char* front,char*midlle,int num)
    {
        int i=0;
        (*root)->data=front[0];
        if (num==0)
        {
            return;
        }
        //找到根节点在middle所在的位置
        for (i=0;i<num;i++)
        {
            if ((*root)->data==midlle[i])
            {
                break;
            }
        }
        if (i!=0)//如果root存在左孩子
        {
            (*root)->lChild=new struct BiTNode();
            initTree(&(*root)->lChild,front+1,midlle,i);
        }
        if (i!=num-1)//如果root存在右孩子
        {
            (*root)->rChild=new struct BiTNode();
            initTree(&(*root)->rChild,front+i+1,midlle+i+1,num-i-1);
        }
        return;
    }
    

    非递归实现前、中、后序遍历

    //前序
    void PreOrder(BiTNode *root)
    {
        stack<BiTNode*> stackNode;
        BiTNode *cur=root;
    
        while (cur!=NULL||!stackNode.empty())
        {
            //每次将当前结点访问了,然后入栈
            //当while循环结束的时候,cur指向最左结点的左结点为NULL
            while (cur!=NULL)
            {
                cout<<cur->data<<endl;
                stackNode.push(cur);
                cur=cur->lChild;
    
            }
            //while循环出来表示整个数的根结点和其左子树的根结点均已被打印;
            //现在要做的是从下往上一次打印左右节点;
            if (!stackNode.empty())
            {
                cur=stackNode.top();//取出最左结点;
                stackNode.pop();//将最左结点出栈
                cur=cur->rChild;
    
            }
        }
    
    }
    
    
    
    //中序
    void InOrder(BiTNode *root)
    {
        stack<BiTNode*>stackNode;
        BiTNode *cur=root;
        while(cur!=NULL||!stackNode.empty())
        {
            while(cur!=NULL)
            {
                stackNode.push(cur);
                cur=cur->lChild;
            }
    
            if (!stackNode.empty())
            {
                cur=stackNode.top();
                cout<<cur->data<<endl;
                cur=cur->rChild;
            }
        }
    }
    
    
    //后序
    void PostOrder(BiTNode *root)
    {
       BiTNode *cur=root;//当前节点
       BiTNode *pre=NULL; //上一次打印的节点
       stack<BiTNode*> stackNode;
       //只有当前节点或者栈中还有元素,则该二叉树一定还没有打印完
       while(cur!=NULL||!stackNode.empty())
       {
           while(cur!=NULL)//一直找到最左节点
           {
               stackNode.push(cur);
               cur=cur->lChild;
           }
    
           if (!stackNode.empty())
           {
               BiTNode *node=stackNode.top();//取出最左节点
               //如果节点的右孩子为空,或者右孩子已经被打印,则可以打印本节点
               if (node->rChild==NULL||node->rChild==pre)
               {
                   cout<<node->data<<endl;
                   stackNode.pop();
                   pre=node;//将pre更新为已经打印过的节点
               }
               //如果节点的右孩子不为空,且没有被访问过,则将cur更新为右孩子,继续whiile循环
               else
               {
                   cur=node->rChild;
               }
    
           }
       }
    }
    

    递归方式计算树的深度

    采用后序遍历,先计算左子树的深度,再计算右子树的深度,最后取较大者加1即为二叉树的深度。

    int PostOrderTreeDepth(BiTNode *root)
    {
        int leftDepth,rightDepth,maxDepth;
        if(root!=NULL)
        {
            leftDepth=PostOrderTreeDepth(root->lChild);
            rightDepth=PostOrderTreeDepth(root->rChild);
            maxDepth=leftDepth>rightDepth?leftDepth:rightDepth;
            return (maxDepth+1);
        }
        else
        {
            return 0;
        }
    }
    

    非递归计算数的深度

    采用层次遍历的方法:

    ①每遍历一层,depth++

    ②每一层,用一个变量len记录该层的节点个数,也就是队列的当前长度,然后依次在队列中访问该层的len个节点(将队列中len个元素出队列),并将下一层入队列。

    int TreeDepth(BiTNode *root)
    {
        queue <BiTNode*> q;
        int level=0;
        int len;
        BiTNode *temp;
        if (root==NULL)
        {
            return 0;
        }
        q.push(root);
        while (!q.empty())
        {
            level++;
            len=q.size();
            while(len--)
            {
                temp=q.front();
                q.pop();
                if (temp->lChild)
                {
                    q.push(temp->lChild);
                }
                if (temp->rChild)
                {
                    q.push(temp->rChild);
                }
    
            }
    
        }
        return level;
    }
    

    算法

    topK

    利用堆排序,建立一个大小为k的大顶堆,遍历n个数字,若比堆顶元素小,则取代之,并将堆更新保持大顶堆。 那么只需要遍历一次n,然后输出大小为k的最终的大顶堆。 即为最小的k个数字。O(nlogk)

    void HeapAdjustTest(int a[],int len)
    {
        int index=len/2-1;
        for (int i=index;i>=0;i--)
        {
            int childIndex=2*i+1;
            if (childIndex<len && childIndex+1<len)
            {
                if (a[childIndex]>a[childIndex+1])
                {
                    childIndex++;
                }
            }
            if (a[i]>a[childIndex])
            {
                swap(a[i],a[childIndex]);
            }
        }
    }
    void topK(int input[],int output[],int n,int k)
    {
        int min;
        for (int i=0;i<k;i++)
        {
            output[i]=input[i];
        }
    
        HeapAdjustTest(output,k);
        min=output[0];
        for(int j=k;j<n;j++)
        {   
            if (input[j]>min)
            {
                swap(output[0],input[j]);
                HeapAdjustTest(output,k);
                min=output[0];
            }
    
        }
    }
    
    • 0
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值