1.1链表拓展题

循环链表题

1 约瑟夫环

  • 背景

    据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
    然而Josephus和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

  • 问题1

    41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止,把41个人自杀的顺序编号输出。

  • 代码1

    //n个人围圈报数,报m出列,最后剩下的是几号?
    
        #include <stdio.h>
        #include <stdlib.h>
    
    typedef struct node
    {
        int data;
        struct node *next;
    }node;
    
    node *create(int n)
    {
        node *p = NULL, *head;
        head = (node*)malloc(sizeof (node ));
        p = head;
        node *s;
        int i = 1;
    
        if( 0 != n )
        {
            while( i <= n )
            {
                s = (node *)malloc(sizeof (node));
                s->data = i++;    // 为循环链表初始化,第一个结点为1,第二个结点为2。
                p->next = s;
                p = s;
            }
            s->next = head->next;
        }
    
        free(head);
    
        return s->next ;
    }
    
    int main()
    {
        int n = 41;
        int m = 3;
        int i;
        node *p = create(n);
        node *temp;
    
        m %= n;   // m在这里是等于2
    
        while (p != p->next )
        {
            for (i = 1; i < m-1; i++)
            {
                p = p->next ;
            }
    
            printf("%d->", p->next->data );
    
            temp = p->next ;                //删除第m个节点
            p->next = temp->next ;
            free(temp);
    
            p = p->next ;
        }
    
        printf("%d\n", p->data );
    
        return 0;
    }
  • 问题2

    编号为1~N的N个人按顺时针方向围坐一圈,每人持有一个密码(正整数,可以自由输入),开始人选一个正整数作为报数上限值M,从第一个人按顺时针方向自1开始顺序报数,报道M时停止报数。报M的人出列,将他的密码作为新的M值,从他顺时针方向上的下一个人开始从1报数,如此下去,直至所有人全部出列为止。

  • 代码2

        #include <stdio.h>
        #include <stdlib.h>
        #define MAX_NODE_NUM 100
        #define TRUE 1U
        #define FALSE 0U
    
        typedef struct NodeType
        {
            int id;
            int cipher;
            struct NodeType *next;
        } NodeType;
    
        /* 创建单向循环链表 */
        static void CreaList(NodeType **, const int);
        /* 运行"约瑟夫环"问题 */
        static void StatGame(NodeType **, int);
        /* 打印循环链表 */
        static void PrntList(const NodeType *);
        /* 得到一个结点 */
        static NodeType *GetNode(const int, const int);
        /* 测试链表是否为空, 空为TRUE,非空为FALSE */
        static unsigned EmptyList(const NodeType *);
    
        int main(void)
        {
            int n, m;
            NodeType *pHead = NULL;
            while (1)
            {
                printf("请输入人数n(最多%d个): ", MAX_NODE_NUM);
                scanf("%d", &n);
                printf("和初始密码m: ");
                scanf("%d", &m);
                if (n > MAX_NODE_NUM)
                {
                    printf("人数太多,请重新输入!\n");
                    continue;
                }
                else
                    break;
            }
            CreaList(&pHead, n);
            printf("\n------------ 循环链表原始打印 -------------\n");
            PrntList(pHead);
            printf("\n-------------删除出队情况打印 -------------\n");
            StatGame(&pHead, m);
        }
    
        static void CreaList(NodeType **ppHead, const int n)
        {
            int i, iCipher;
            NodeType *pNew, *pCur;
            for (i = 1; i <= n; i++)
            {
                printf("输入第%d个人的密码: ", i);
                scanf("%d", &iCipher);
                pNew = GetNode(i, iCipher);
                if (*ppHead == NULL)
                {
                    *ppHead = pCur = pNew;
                    pCur->next = *ppHead;
                }
                else
                {
                    pNew->next = pCur->next;
                    pCur->next = pNew;
                    pCur = pNew;
                }
            }
            printf("完成单向循环链表的创建!\n");
        }
    
        static void StatGame(NodeType **ppHead, int iCipher)
        {
            int iCounter, iFlag = 1;
            NodeType *pPrv, *pCur, *pDel;
            pPrv = pCur = *ppHead;
            /* 将pPrv初始为指向尾结点,为删除作好准备 */
            while (pPrv->next != *ppHead)
                pPrv = pPrv->next;
            while (iFlag)
            {
                for (iCounter = 1; iCounter < iCipher; iCounter++)
                {
                    pPrv = pCur;
                    pCur = pCur->next;
                }
                if (pPrv == pCur)
                    iFlag = 0;
                pDel = pCur; /* 删除pCur指向的结点,即有人出列 */
                pPrv->next = pCur->next;
                pCur = pCur->next;
                iCipher = pDel->cipher;
                printf("第%d个人出列, 密码: %d\n", pDel->id, pDel->cipher);
                free(pDel);
            }
            *ppHead = NULL;
            getchar();
        }
    
        static void PrntList(const NodeType *pHead)
        {
            const NodeType *pCur = pHead;
            if (EmptyList(pHead))
                return;
            do
            {
                printf("第%d个人, 密码: %d\n", pCur->id, pCur->cipher);
                pCur = pCur->next;
            }
            while (pCur != pHead);
            getchar();
        }
    
        static NodeType *GetNode(const int iId, const int iCipher)
        {
            NodeType *pNew;
            pNew = (NodeType *)malloc(sizeof(NodeType));
            if(!pNew)
            {
                printf("Error, the memory is not enough!\n");
                exit(-1);
            }
            pNew->id = iId;
            pNew->cipher = iCipher;
            pNew->next = NULL;
            return pNew;
        }
    
        static unsigned EmptyList(const NodeType *pHead)
        {
            if(!pHead)
            {
                printf("The list is empty!\n");
                return TRUE;
            }
            return FALSE;
        }

2 判断链表是否有环

  • 有环的定义:链表的尾节点指向了链表中的某个节点。

    这里写图片描述

  • 题目

  • 思路

    • 方法一:使用p、q两个指针,p总是向前走,但q每次都从头开始走,对于每个节点,看p走的步数是否和q一样。如图,当p从6走到3时,用了6步,此时若q从head出发,则只需两步就到3,因而步数不等,出现矛盾,存在环。(效率低,相当于暴力穷举)

    • ☆方法二:快慢指针。使用p、q两个指针,p每次向前走一步,q每次向前走两步,若在某个时候p == q,则存在环。

    • 代码

        #include "stdio.h"
        #define OK 1
        #define ERROR 0
        #define TRUE 1
        #define FALSE 0
    
    typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
    typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */
    
    typedef struct Node
    {
        ElemType data;
        struct Node *next;
    }Node, *LinkList;
    
    /* 初始化带头结点的空链表 */
    Status InitList(LinkList *L)
    {
        *L = (LinkList)malloc(sizeof(Node)); /* 产生头结点,并使L指向此头结点 */
    
        if(!(*L)) /* 存储分配失败 */
                return ERROR;
    
        (*L)->next=NULL; /* 指针域为空 */
    
        return OK;
    }
    
    /* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */
    int ListLength(LinkList L)
    {
        int i=0;
        LinkList p=L->next; /* p指向第一个结点 */
        while(p)
        {
            i++;
            p=p->next;
        }
        return i;
    }
    
    /*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
    void CreateListHead(LinkList *L, int n)
    {
        LinkList p;
        int i;
    
        srand(time(0));                         /*  初始化随机数种子 */
    
        *L = (LinkList)malloc(sizeof(Node));
        (*L)->next = NULL;                      /*  建立一个带头结点的单链表 */
    
        for (i=0; i < n; i++)
        {
            p = (LinkList)malloc(sizeof(Node)); /*  生成新结点 */
            p->data = rand()%100+1;             /*  随机生成100以内的数字 */
            p->next = (*L)->next;
            (*L)->next = p;                     /*  插入到表头 */
        }
    }
    
    /*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
    void CreateListTail(LinkList *L, int n)
    {
        LinkList p,r;
        int i;
    
        srand(time(0));                      /* 初始化随机数种子 */
        *L = (LinkList)malloc(sizeof(Node)); /* L为整个线性表 */
        r = *L;                              /* r为指向尾部的结点 */
    
        for (i=0; i < n; i++)
        {
            p = (Node *)malloc(sizeof(Node)); /*  生成新结点 */
            p->data = rand()%100+1;           /*  随机生成100以内的数字 */
            r->next=p;                        /* 将表尾终端结点的指针指向新结点 */
            r = p;                            /* 将当前的新结点定义为表尾终端结点 */
        }
    
        r->next = (*L)->next->next;
    }
    
    // 比较步数的方法(方法1)
    int HasLoop1(LinkList L)
    {
        LinkList cur1 = L;  // 定义结点 cur1
        int pos1 = 0;       // cur1 的步数
    
        while(cur1)
        {                       // cur1 结点存在
            LinkList cur2 = L;  // 定义结点 cur2
            int pos2 = 0;       // cur2 的步数
            while(cur2)
            {                           // cur2 结点不为空
                if(cur2 == cur1)
                {                       // 当cur1与cur2到达相同结点时
                    if(pos1 == pos2)    // 走过的步数一样
                        break;          // 说明没有环
                    else                // 否则
                    {
                        printf("环的位置在第%d个结点处。\n\n", pos2);
                        return 1;       // 有环并返回1
                    }
                }
                cur2 = cur2->next;      // 如果没发现环,继续下一个结点
                pos2++;                 // cur2 步数自增
            }
            cur1 = cur1->next;  // cur1继续向后一个结点
            pos1++;             // cur1 步数自增
        }
        return 0;
    }
    
    // 利用快慢指针的方法(方法2)
    int HasLoop2(LinkList L)
    {
        int step1 = 1;
        int step2 = 2;
        LinkList p = L;
        LinkList q = L;
    
        while (p != NULL && q != NULL && q->next != NULL)
        {
            p = p->next;
            if (q->next != NULL)
                q = q->next->next;
    
            printf("p:%d, q:%d \n", p->data, q->data);
    
            if (p == q)
                return 1;
        }
        return 0;
    }
    
    int main()
    {
        LinkList L;
        Status i;
        char opp;
        ElemType e;
        int find;
        int tmp;
    
        i = InitList(&L);
        printf("初始化L后:ListLength(L)=%d\n",ListLength(L));
    
        printf("\n1.创建有环链表(尾插法) \n2.创建无环链表(头插法) \n3.判断链表是否有环 \n0.退出 \n\n请选择你的操作:\n");
        while(opp != '0')
        {
            scanf("%c",&opp);
            switch(opp)
            {
                case '1':
                    CreateListTail(&L, 10);
                    printf("成功创建有环L(尾插法)\n");
                    printf("\n");
                    break;
    
                case '2':
                    CreateListHead(&L, 10);
                    printf("成功创建无环L(头插法)\n");
                    printf("\n");
                    break;
    
                case '3':
                    printf("方法一: \n\n");
                    if( HasLoop1(L) )
                    {
                        printf("结论:链表有环\n\n\n");
                    }
                    else
                    {
                        printf("结论:链表无环\n\n\n");
                    }
    
                    printf("方法二:\n\n");
                    if( HasLoop2(L) )
                    {
                        printf("结论:链表有环\n\n\n");
                    }
                    else
                    {
                        printf("结论:链表无环\n\n\n");
                    }
                    printf("\n");
                    break;
    
                case '0':
                    exit(0);
            }
        }
    
    }

3 魔术师发牌问题

  • 问题描述

    魔术师手中有A、2、3……J、Q、K十三张黑桃扑克牌。在表演魔术前,魔术师已经将他们按照一定的顺序叠放好(有花色的一面朝下)。魔术表演过程为:一开始,魔术师数1,然后把最上面的那张牌翻过来,是黑桃A;然后将其放到桌面上;第二次,魔术师数1、2;将第一张牌放到这些牌的最下面,将第二张牌翻转过来,正好是黑桃2;第三次,魔术师数1、2、3;将第1、2张牌依次放到这些牌的最下面,将第三张牌翻过来正好是黑桃3;……直到将所有的牌都翻出来为止。问原来牌的顺序是如何的。

    #include <stdio.h>
    #include <stdlib.h>
    
    #define  CardNumber 13
    
    typedef struct node
    {
        int data;
        struct node *next;
    }sqlist, *linklist;
    
    linklist CreateLinkList()
    {
        linklist head = NULL;
        linklist s, r;
        int i;
    
        r = head;
    
        for(i=1; i <= CardNumber; i++)
        {
            s = (linklist)malloc(sizeof(sqlist));
            s->data = 0;
    
            if(head == NULL)
                head = s;
            else
                r->next = s;
    
            r = s;
        }
    
        r->next = head;
    
        return head;
    }
    
    // 发牌顺序计算
    void Magician(linklist head)
    {
        linklist p;
        int j;
        int Countnumber = 2;
    
        p = head;
        p->data = 1;  //第一张牌放1
    
        while(1)
        {
            for(j=0; j < Countnumber; j++)
            {
                p = p->next;
                if(p->data != 0)  //该位置有牌的话,则下一个位置
                {
                    p->next;
                    j--;
                }
            }
    
            if(p->data == 0)
            {
                p->data = Countnumber;
                Countnumber ++;
    
                if(Countnumber == 14)
                    break;
            }
        }
    }
    
    // 销毁工作(不必要)
    void DestoryList(linklist* list)
    j
    }
    
    int main()
    {
        linklist p;
        int i;
    
        p = CreateLinkList();
        Magician(p);
    
        printf("按如下顺序排列:\n");
        for (i=0; i < CardNumber; i++)
        {
            printf("黑桃%d ", p->data);
            p = p->next;
        }
    
        DestoryList(&p);
    
        return 0;
    }
    

4 拉丁方阵问题

  • 问题描述

    拉丁方阵是一种n×n的方阵,方阵中恰有n种不同的元素,每种元素恰有n个,并且每种元素在一行和一列中 恰好出现一次。

    这里写图片描述

  • 代码

    
    #include<iostream>  
    
    using namespace std;  
    /************************************************** 
    *数据储存结构,循环链表。 
    *************************************************/  
    struct HanNode{  
        int data;  
        HanNode * nextPtr;  
    };  
    /************************************************** 
    *创建循环链表 
    *************************************************/  
    HanNode * create(int amount)  
    {  
        if (amount == 1)  
        {  
            HanNode * head = new HanNode;  
            head->data = 1;  
            head->nextPtr = head;  
            return head;  
        }  
        else{  
            HanNode * head = new HanNode;  
            head->data = 1;  
            head->nextPtr = head;  
            HanNode * preNode = head;  
            HanNode * newNode = 0;  
            int i = 1;  
            while (i < amount)  
            {  
                ++i;  
                newNode = new HanNode;  
                newNode->data = i;  
                newNode->nextPtr = head;  
                preNode->nextPtr = newNode;  
                //|  
                preNode = newNode;  
    
            }  
            return head;  
    
        }  
    }  
    /************************************************** 
    *输出拉丁方阵 
    *************************************************/  
    void PrintLatinSquare(HanNode * head,int amount)  
    {  
        HanNode * tmpNode = 0;  
        cout << "拉丁方阵输出:" << endl;  
        for (int i = 1; i <= amount; i++)  
        {  
            if (i == 1)  
            {  
                tmpNode = head;  
            }  
            else{  
                int j = 1;  
                tmpNode = head;  
                while (j < i)  
                {  
                    ++j;  
                    tmpNode = tmpNode->nextPtr;  
                }  
            }  
            for (int j = 1; j <= amount; j++)  
            {  
                cout << tmpNode->data << ",";  
                tmpNode = tmpNode->nextPtr;  
            }  
            //|换行  
            cout << endl;  
        }  
    }  
    /************************************************** 
    *销毁拉丁方阵 
    *************************************************/  
    void Destroy(HanNode * head)  
    {  
        if (head == head->nextPtr)  
        {  
            delete head;  
        }  
        else{  
    
            HanNode * tmpdel = head->nextPtr;  
            HanNode * del = 0;  
            while (tmpdel != head)  
            {  
                del = tmpdel;  
                tmpdel = tmpdel->nextPtr;  
                delete del;  
            }  
            delete head;  
        }  
    }  
    /************************************************** 
    *主函数(入口) 
    *************************************************/  
    int main(int argc, char *argv[])  
    {  
        /*HanNode * p = create(5); 
        //|遍历(调试看看) 
        HanNode * tmp = p; 
        for (int i = 1; i <= 5; i++) 
        { 
            cout << tmp->data << endl; 
            tmp = tmp->nextPtr; 
        } 
        //|输出拉丁方阵 
        PrintLatinSquare(p, 5); 
        //|销毁 
        Destroy(p); 
        */  
        //|循环  
        int i = 1;  
        int amount = 0;  
        HanNode * pLatinSquare = 0;  
        while (i)  
        {  
            cout << "输出要生成的拉丁方阵的大小:(整数)" << endl;  
            cin >> amount;  
            //|创建拉丁方阵  
            pLatinSquare = create(amount);  
            //|输出拉丁方阵  
            PrintLatinSquare(pLatinSquare, amount);  
            //|销毁拉丁方阵  
            Destroy(pLatinSquare);  
            //|  
            cout << "输入1继续,0退出" << endl;  
            cin >> i;  
    
        }  
        return 1;  
    } 
    
  • 运行结果

    输出要生成的拉丁方阵的大小:(整数)  
    10  
    拉丁方阵输出:  
    1,2,3,4,5,6,7,8,9,10,  
    2,3,4,5,6,7,8,9,10,1,  
    3,4,5,6,7,8,9,10,1,2,  
    4,5,6,7,8,9,10,1,2,3,  
    5,6,7,8,9,10,1,2,3,4,  
    6,7,8,9,10,1,2,3,4,5,  
    7,8,9,10,1,2,3,4,5,6,  
    8,9,10,1,2,3,4,5,6,7,  
    9,10,1,2,3,4,5,6,7,8,  
    10,1,2,3,4,5,6,7,8,9,  
    输入1继续,0退出  

5 链表连接(循环链表)

  • 题目

    实现将两个线性表(a1,a2,…,an)和(b1,b2,…,bm)连接成一个线性表(a1,…,an,b1,…bm)的运算。

  • 分析:

    若在单链表或头指针表示的单循环表上做这种链接操作,都需要遍历第一个链表,找到结点an,然后将结点b1链到an的后面,其执行时间是O(n)。

    若在尾指针表示的单循环链表上实现,则只需修改指针,无须遍历,其执行时间是O(1)。

    这里写图片描述

//假设A,B为非空循环链表的尾指针
LinkList Connect(LinkList A,LinkList B)
{   
    LinkList p = A->next;       //保存A表的头结点位置

    A->next = B->next->next;    //B表的开始结点链接到A表尾

    free(B->next);  //释放B表的头结点,初学者容易忘记

    B->next = p;        

    return B;       //返回新循环链表的尾指针
} 

6 双向循环链表

  • 题目1:

    要求实现用户输入一个数使得26个字母的排列发生变化,例如用户输入3,输出结果:
    DEFGHIJKLMNOPQRSTUVWXYZABC
    同时需要支持负数,例如用户输入-3,输出结果:
    XYZABCDEFGHIJKLMNOPQRSTUVW

  • 代码

#include<stdio.h>
#include<stdlib.h>

#define OK 1
#define ERROR 0;

typedef char ElemType;
typedef int Status;
typedef struct DualNode
{
    ElemType data;
    struct DualNode *prior;
    struct DualNode *next;
}DualNode,*DuLinkList;

Status InitList(DuLinkList *L)
{
    DualNode *p,*q;
    int i;

    *L=(DuLinkList)malloc(sizeof(DualNode));

    if(!(*L))
    {
        return ERROR;
    }

    (*L)->next=(*L)->prior=NULL;
    p=(*L);

    for(i=0;i<26;i++)
    {
        q=(DualNode *)malloc(sizeof(DualNode));
        if(!q)
        {
            return ERROR;
        }

        q->data='A'+i;
        q->prior=p;
        q->next=p->next;
        p->next=q;
        p=q;
    }

    p->next=(*L)->next;
    (*L)->next->prior=p;

    return OK;
}

void caser(DuLinkList *L,int i)
{
    if(i>0)
    {
         do
         {
            (*L)=(*L)->next;
         }while(--i);

    }
    if(i<0)
    {
        i=i-1;
        (*L)=(*L)->next;

        do
        {
            (*L)=(*L)->prior;
        }while(++i);
    }

}

int main()
{
    DuLinkList L;
    int i,n;

    InitList(&L);
    printf("请输入一个整数:\n");
    scanf("%d",&n);
    printf("\n");

    caser(&L,n);

    for(i=0;i<26;i++)
    {
        L=L->next;
        printf("%c",L->data);
    }

    printf("\n");

    return 0;
}
  • 题目2

    Vigenere(维吉尼亚)加密:当输入明文,自动生成随机密匙匹配明文中每个字母并移位加密。

    这里写图片描述

建议:当然你的随机密匙生成后不能丢掉,丢掉了就很难把明文还原来了,建议把随机密匙和密文加密存储在一起。

能在根目录创建一个文件夹保存当前的密钥, 随机密钥和加密后密钥(3天后解密)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>


#define TRUE 1
#define FALSE 0

/*定义加密的结构*/
typedef struct Node_
{
    int data;
    struct Node_ *prev;
    struct Node_ * next;
}Node;

typedef Node * List;

void InitList (List *plist);//初始化链表

int CreateList (List *plist, int n); //创建26个字母的链表

int  Search (List *plist, int n, char okey); //通过随机密码实现加密



void Encryption (List *plist, char * str, int **tkeys, char **eKeys); // 通过字典加密

char * getstr (void); //获取要加密的密钥

int main (void)
{
    List lists;
    char *password; // 原始密钥
    int *tKeys;   //随机密钥
    char *eKeys;  //加密密钥
    FILE *fp; // 创建文件指针
    int i;


    srand ((unsigned)time(NULL)); //初始化随机函数种子

    InitList (&lists);
    CreateList (&lists, 26);  //创建26大写字母的字典
    password = getstr ();  //获取任意长度的字符串
    Encryption (&lists, password,&tKeys, &eKeys); //获取随机密钥并且加密
    system ("pause");
    if ((fp = fopen ("keys.txt", "w+")) == NULL)  //创建名为keys.txt的文件
    {
        fprintf (stdout, "Can't open keys.txt file.\n"); //创建文件失败
        exit(1);
    }
    /*下面的都是把相应数据写入文件*/
    fprintf (fp,"密码:");
    fputs (password, fp);
    fprintf (fp, "\n");

    fprintf (fp,"随机密钥:");
    for (i = 0; i < strlen(password); i++)
        fprintf (fp, "%d ", tKeys[i]);

    fprintf (fp, "\n加密:");
    fputs (eKeys, fp);
    free (&tKeys);
    free (&eKeys);
    free (password);
    if (fclose(fp) == NULL) // 关闭文件
    {
        fprintf (stderr, "Error closing file\n");
        exit(1);
    }

    return 0;
}

void InitList (List *plist)
{
    *plist = NULL;
}

int CreateList (List *plist, int n)//创建双向链表
{
    Node *pnode = *plist;
    Node *pnew;
    int i;

    for (i = 0; i < n; i++)
    {
        pnew = (Node*) malloc (sizeof (Node));
        if (pnew == NULL)
            return FALSE;
        pnew->data = 65+i; // 存入数据
        pnew->prev = NULL;
        pnew->next = NULL;

        if (pnode == NULL) //当表是空表时
        {
            *plist = pnew;
            pnode = *plist;
            pnew->prev = pnode;
            pnew->next = pnode;
        }

        pnew->next = pnode->next;   //新节点指头前节点的next节点
        pnew->prev = pnode;          //新节点的前驱指向头节点
        pnew->next->prev = pnew;    //头节点的next节点的前驱指向新节点
        pnode->next = pnew;         //头节点的next指针指向新节点
        pnode = pnode->next;        //更新头节点地址
    }
    return TRUE;
}


 int Search (List *plist, int n, char okey)
 {
    Node * pscan = *plist;

    int i;
    int nkey;
    while (pscan->data != okey) //初始化需加密字母位置
        pscan = pscan->next;

    for (i = 0; i< n; i++)
    {
        pscan = pscan->next;
    }
    nkey = pscan->data; //获取加密后字母
    return nkey;
 }

void Encryption (List *plist, char * str, int **tKeys, char **eKeys)
{
    int tKey;
    int num;
    int i;



    num = strlen (str); //获取密钥长度

    (*tKeys) = (int *) malloc (sizeof (int) * (num));    //建立存储随机密钥的数组
    (*eKeys) = (char *) malloc (sizeof (char) * (num+1));//建立存储加密密钥的字符串
    for (i = 0; i < num; i++)
    {
        tKey = rand() % 1000;  //获取随机密钥
        (*tKeys)[i] = tKey;    // 存入数组
        (*eKeys)[i] = Search (plist, tKey, toupper(str[i])); // 获取加密后字母
    }
    (*eKeys)[i] = '\0'; //添加字符串结尾
    printf ("原始密钥:");
    puts (str);
    printf ("随机密钥:");
    for (i = 0; i < num; i++)
    {
        printf ("%d ", (*tKeys)[i]);
    }
    putchar ('\n');
    printf ("加密密钥:");
    puts (*eKeys);

}

char * getstr (void) // 动态获取字符串
{
    char *str;

    int i = 1;

    printf ("请输入要加密的密钥(A-Z大写字母):");
    str = (char*) malloc (sizeof (char) * (i+1));
    while ((str[i-1] = getchar ()) != '\n')
    {
        i++;
        str = (char*)realloc (str, sizeof (char) *(i+1));
        if (str == NULL)
        {
            printf ("No enough memory!");
            return FALSE;
        }

    }
    str[i-1] = '\0';
    return str;
}

7 快慢指针-链表

  • 题目:快速找到未知长度单链表的中间节点。

  • 普通方法:首先遍历一遍链表以确定链表的长度L。然后再次从头节点出发循环L/2次找到单链表的中间节点。算法复杂度为:O(L+L/2)=O(3L/2)。

  • 利用快慢指针原理:设置两个指针search、*mid都指向单链表的头节点。其中 search的移动速度是*mid的2倍。当*search指向末尾节点的时候,mid正好就在中间了。这也是标尺的思想。算法复杂度为:O(L/2)。

  • 程序

Status GetMidNode(LinkList L, ElemType *e)
{
    LinkList search, mid;
    mid = search = L;

    while (search->next != NULL)
    {
        //search移动的速度是 mid 的2倍
        if (search->next->next != NULL)
        {
            search = search->next->next;
            mid = mid->next;
        }
        else
        {
            search = search->next;  //还有一个元素才指向末尾的情况
        }
    }

    *e = mid->data;

    return OK;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值