啊哈,算法自学记——4th

链表

有一串已经从小到大排好序的数 2 3 5 8 9 10 18 26 32。现需要往这串数中插入 6 使其得到的新序列仍符合从小到大排列。
先回顾下指针:(主要是我不太了解…)

int *p;

指针有什么作用呢?
答案是:存储一个地址。确切地说是存储一个内存空间的地址。严格地说这里的指针 p 也只能存储“一个存放整数的内存空间”的地址,因为在定义的时候我们已经限制了这一点(即定义的时候*p 的前面是 int)。
当然你也可以定义一个只能用来存储“一个存放浮点数的内存空间”的地址,如:

double *p;

整型指针 p 如何才能存储整型变量 a 的地址呢?

p=&a;//&取地址符

有什么用呢?用处就是我们可以用指针 p 来操作变量 a 了。比如我们可以通过操作指针 p 来输出变量 a 的值:

#include <stdio.h>
int main()
{
	int a=10;
	int *p; //定义个指针p
	p=&a; //指针p获取变量a的地址
	printf("%d",*p); //输出指针p所指向的内存中的值
	return 0;
}

MALLOC函数:
malloc 函数的返回类型是 void * 类型。 void * 表示未确定类型的指针。在 C和 C++中, void * 类型可以强制转换为任何其他类型的指针。

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int *p; //定义一个指针p
	p=(int *)malloc(sizeof(int)); //指针p获取动态分配的内存空间地址
	*p=10; //向指针p所指向的内存空间中存入10
	printf("%d",*p); //输出指针p所指向的内存中的值
	return 0;
}

链表每一个结点都由两个部分组成。
左边的部分用来存放具体的数值,那么用一个整型变量就可以;
右边的部分需要存储下一个结点的地址,可以用指针来实现

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

//创建一个结构体来表示链表的结点类型
typedef struct node
{
    int data;
    struct node *next;  
};


int main(int argc, char const *argv[])
{
    struct node *head,*p,*q,*t;
    int n,a;

    printf("Input the num of data:
");
    scanf("%d",&n);

    head=NULL;//头指针指向空

    printf("Input the data:
");
    for (int i = 0; i < n; i++)
    {
        scanf("%d",&a);
        //动态申请一个内存,用来存放一个结点,并用临时指针指向这个结点
        p=(struct node *)malloc(sizeof(struct node));
        /*->叫做结构体指针运算符,也是用来访问结构体内部成员的。
        因为此处 p 是一个指针,所以不能使用.号访问内部成员,而要使用->*/
        p->data=a;//将数据存储到当前结点的数据域中
        p->next=NULL;//设置当前结点的后继指针为空,也就是当前结点的下一个结点为空
        if (head==NULL)//
        {
            head=p;//如果这是第一个创建的结点,则将头指针指向这个结点
        }
        else
        {
            q->next=p;//如果不是第一个创建的结点,则将上一个结点的后继指针指向当前结点
        }
        q=p;//指针q也指向当前结点    
    }
    
    /*插入新的结点*/
    printf("Input the num of insert:
");
    scanf("%d",&a);

    t=head;//
    while (t!=NULL)//遍历链表
    {
        if(t->next->data > a)//如果下一个结点的数据大于插入的数
        {
            p=(struct node *)malloc(sizeof(struct node));//动态申请
            p->data=a;//存入数据
            p->next=t->next;//新增指针的后继指针指向当前结点的后继指针所指向的结点。。。晕
            t->next=p;//当前结点的后继指针指向新增结点
            break;//插入完毕,退出

        }
        t=t->next;
    }
    

    //输出链表中的所有数
    t=head;
    while (t!=NULL)
    {
        printf("  %d",t->data);
        t=t->next;
    }
    free(p);
    return 0;
}

在这里插入图片描述

**

模拟链表:

**
如果你觉得上一节的代码简直是天书,或者你压根就很讨厌指针这些东西,没关系!链表还有另外一种使用数组来实现的方式,叫做模拟链表,我们一起来看看

链表中的每一个结点只有两个部分。我们可以用一个数组 data 来存储每序列中的每一个数。那每一个数右边的数是谁,这一点该怎么解决呢?上一节中是使用指针来解决的,这里我们只需再用一个数组 right 来存放序列中每一个数右边的数是谁就可以了,具体怎么做呢?

在这里插入图片描述
上图的两个数组中,第一个整型数组 data 是用来存放序列中具体数字的,另外一个整型数组 right 是用来存放当前序列中每一个元素右边的元素在数组 data 中位置的。例如 right[1]的值为 2,就表示当前序列中 1 号元素右边的元素存放在 data[2]中;如果是 0,例如right[9]的值为 0,就表示当前序列中 9 号元素的右边没有元素。

看完就晕了,说说我自己的理解:
简单来说就是把上面链表的地址用数组下标来表示,用另一个数组来存放数据数组中的数对应的下标,也即链表中的后继指针,有理解错的地方,希望有心人能给我指正下。

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int data[101],right[101];
    int n,t,len;
    printf("Input the num of data:
");
    scanf("%d",&n);

    printf("Input the data:
");
    for (int i = 1; i <= n; i++)
    {
        scanf("%d",&data[i]);
    }
    len=n;
    //初始化right数组
    for (int i = 1; i <= n; i++)
    {
        if(i!=n)
            right[i]=i+1;
        else
            right[i]=0;
    }
    
    //在data末尾加上一个数据
    len++;
    printf("Input the num of insert:
");
    scanf("%d",&data[len]);

    //从链表的头部开始遍历
    t=1;
    while (t!=0)
    {
       if (data[right[t]]>data[len])//如果当前结点的下一个结点的数大于待插入的数据,将数插入到中间
       {
            right[len]=right[t];//新插入数的下一个结点标号等于当前结点的下一个编号
            right[t]=len;//当前结点的下一个节点编号就是新插入书的结点编号
            break;
       }
       t=right[t];
    }
    //打印
    t=1;
    while (t!=0)
    {
        printf(" %d",data[t]);
        t=right[t];
    }
    
    return 0;
}

在这里插入图片描述

原文地址:https://www.cnblogs.com/hhsxy/p/14018431.html