链表·杂烩

来源:互联网 发布:网络pxe rom启动选择 编辑:程序博客网 时间:2024/05/01 08:00

1.单向链表   

    单向链表的反转是一个经常被问到的一个面试题,也是一个非常基础的问题。比如一个链表是这样的: 1->2->3->4->5 通过反转后成为5->4->3->2->1。

    最容易想到的方法遍历一遍链表,利用一个辅助指针,存储遍历过程中当前指针指向的下一个元素,然后将当前节点元素的指针反转后,利用已经存储的指针往后面继续遍历。源代码如下:

       1. struct linka {
       2. int data;
       3. linka* next;
       4. };
       5. void reverse(linka*& head) {
       6. if(head ==NULL)
       7.                   return;
       8. linka *pre, *cur, *ne;
       9. pre=head;
      10. cur=head->next;
      11. while(cur)
      12. {
      13.    ne = cur->next;
      14.    cur->next = pre;
      15.    pre = cur;
      16.    cur = ne;
      17. }
      18. head->next = NULL;
      19. head = pre;
      20. }

 

2.约瑟夫环

约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为j的人开始报数,数到m的那个人出列

#include<stdio.h>
#include<stdlib.h>
typedef struct data{ //定义一个结构体“data”
             int num; //用于存放人的序号
             int val; //用于存放密码
}typedata;
typedef struct node{ //定义一个结构体(结点),其中包含一个数据域和一个指针域
             typedata data; //结构体的嵌套
             struct node *next;
}listnode;
typedef listnode *linklist;
linklist head;

void main()// 进入主函数
{
            int n,i,b,m,j;
            linklist head=(listnode *)malloc(sizeof(listnode)); //申请一个空间(头结点 head)
            listnode *p,*q; //定义两个可以指向结点的指针
            printf("输入总人数:");
            scanf("%d",&n);
            q=head; //用指针q指向头结点

            for(j=1;j<=n;j++) //本次循环主要是将每一个人的数据(包括序号、密码)存入循环链表中
            {
                        printf("请输入第%d号同学的密码:\n",j);
                        scanf("%d",&b); 
                        printf("\n");
                        q->next=(listnode *)malloc(sizeof(listnode));
                        //将头结点的next域指向刚生成的一个结点
                        q=q->next;
                        q->data.val=b; //输入密码
                        q->data.num=j; //输入序号
                        q->next=head->next;

             }
                        //将尾结点的next域指向第一个结点,构成循环链表
                        printf("请任意输入一个数m:");
                        scanf("%d",&m); 
                        if(m<=0) printf("输入错误"); 
            do{

                         i=1;
                        while(i!=m){ //将q指针指向所要输出的结点的前一结点
                        q=q->next;
                        i++;
                        }
                        p=q->next; //p指向输出结点
                        q->next=p->next; //将输出结点的前结点的next域指向输出结点的后结点
                        printf("num:%d\tval:%d\n",p->data.num,p->data.val); //输出
                        m=p->data.val; //取得输出结点的密码
                        free(p); 
            }while(q->next!=q); //只剩最后一个结点时结束
                        printf("num:%d\tval:%d\n",q->data.num,q->data.val); //输出最后一个结点
                        free(q); //释放最后一个结点
                        free(head); //释放头结点
                        printf("约瑟夫环结束,欢迎下次光临~·~\n");
}

3.双向链表

双向链表:每个链表节点除了next指针外还有prev指针。哪个节点next指针指向我,我的prev就指向那个节点。
typedef int ElementType;
typedef struct _NODE
{
struct NODE * next;
struct NODE * prev;
ElementType e;
} NODE;
typedef struct _LIST
{
NODE * head;/*记录链表头*/
unsigned int count;/*记录链表元素个数*/
} LIST;
#define __prev /*用于提示在前面操作*/
双向链表在确定节点前面插入是不用遍历链表的。
比如下面的函数,在一个指定节点前插入一个节点的,其他的就类似了:
NODE * InsertToList( __ prev NODE * node, ElemType elem)
{
if (! list || ! node)
return NULL;

NODE * p = (NODE *)malloc(sizeof(NODE));
if (! p)
return NULL;

p ->e = elem;
p ->prev = node ->prev;/*让两个指针指向同一个地方*/
node ->prev ->next = p;/*断开连接*/
node ->prev = p;/*断开连接*/
p ->next = node;/*完成连接*/

return p;
}

原创粉丝点击