链表与模拟链表

链表中的每一个结点应该如何存储?

  • 每个节点都由两个部分组成。左边的部分用来存放具体的数值,那么用一个整型变量就可以;右边的部分需要存储下一个节点的地址,可以用指针来实现(也称为后继指针)。
  • 这里我们定义一个结构体类型来存储这个节点。
struct node{
    int data;
    struct node *next;
};

上面的代码中,我们定义了一个叫做 node 的结构体类型,这个结构体类型有两个成员。

  • 第一个成员是整型 data ,用来存储具体的数值;
  • 第二个成员是一个指针,用来存储下一个节点的地址。
  • 因为下一个结点的类型也是 struct node ,所以这个指针的类型也必须是 struct node * 类型的指针。

如何建立链表呢?

首先,我们需要一个头指针 head 指向链表的最开始。
当链表还没有建立的时候头指针 head 为空(也可以理解为指向头结点)。

struct node *head;
head = NULL;
//头指针初始为空

现在我们来创建第一个结点,并用临时指针 p 指向这个结点。

struct node *p;
p = (struct node *)malloc(sizeof(struct node));

接下来分别设置新创建的这个结点的左半部分和右半部分。

   scanf("%d", &a);
   p->data = a;
   p->next = NULL;

上面的代码中我们发现了一个很奇怪的符号 “->” 。-> 叫做结构体指针运算符,也是用来访问结构体内部成员的。因为此处 p 是一个指针,所以不能使用 . 号访问内部成员,而要用 ->
下面来设置头指针并设置新创建的结点的 * next 指向空。头指针的作用是方便以后从头遍历整个链表。

if(head=NULL)
       head = p;
       //如果这是第一个创建的结点,则将头指针指向这个结点
       else
           q->next = p;
           //如果不是第一个创建的结点,则将上一个结点的后继指针指向当前结点

最后要将指针 q 也指向当前结点,因为待会儿临时指针 p 将会指向新创建的结点。

q = p;  // 指针q也指向当前结点

完整代码如下:

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

struct node{
    int data;
    struct node *next;
};

int main(){
    struct node *head,*p,*q,*t;
    int i, n, a;
    scanf("%d", &n);
    head = NULL;
    for (i = 1; i <= n;i++){
        scanf("%d", &a);
        p = (struct node *)malloc(sizeof(struct node));
        p->data = a;
        p->next = NULL;
        if(head==NULL)
            head = p;
            else
                q->next = p;
            q = p;
    }
    t = head;
    while(t!=NULL){
        printf("%d", t->data);
        t = t->next;
    }
    getchar();
    getchar();
    return 0;
}

发现这样的定义不是很简洁!
对比下面的代码!

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

typedef struct node{
    int data;
    struct node *next;
} Lnode ,*Linklist;

int main(){
    Linklist head, q, p, t;
    int i, n, a;
    scanf("%d", &n);
    head = NULL;
    for (i = 1; i <= n;i++){
        scanf("%d", &a);
        p = (Linklist)malloc(sizeof(Lnode));
        p->data = a;
        p->next = NULL;
        if(head==NULL)
            head = p;
            else
                q->next = p;
            q = p;
    }
    t = head;
    while(t!=NULL){
        printf("%d", t->data);
        t = t->next;
    }
    getchar();
    getchar();
    return 0;
}
  • 容易发现,这里 struct 前多了 typedef ,这是为了方便定义附加的!
    需要说明的一点是:上面的这段代码没有释放动态申请的空间,虽然这样会很不安全,有兴趣的朋友可以去用 free 命令。

接下来需要往链表中插入a。

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

typedef struct node{
    int data;
    struct node *next;
} Lnode ,*Linklist;

int main(){
    Linklist head, q, p, t;
    int i, n, a;
    scanf("%d", &n);
    head = NULL;
    for (i = 1; i <= n;i++){
        scanf("%d", &a);
        p = (Linklist)malloc(sizeof(Lnode));
        p->data = a;
        p->next = NULL;
        if(head==NULL)
            head = p;
            else
                q->next = p;
            q = p;
    }
    t = head;
    scanf("%d", &a);
    while(t!=NULL){
        if(t->next->data>a){
            p = (Linklist)malloc(sizeof(Lnode));
            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;
    }
    getchar();
    getchar();
    return 0;
}

动态存储方法

malloc 函数的作用是从内存中申请分配指定字节大小的内存空间。

  • 需要注意,malloc 函数的返回类型是 void * 类型。
  • void * 表示未确定类型的指针。
  • 注意当在程序中使用 malloc 函数时需要用到 stdlib.h 头文件。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
	int *p;
	p = (int *)malloc(sizeof(int));
	*p = 10;
	printf("%d", *p);
	getchar();
	getchar();
	return 0;
}

运行结果是:

10


模拟链表

  • 用整型数组 data 存放序列中具体数字
  • 用另外一个整型数组 right 存放当前序列中每一个元素右边的元素在数组 data 中的位置。

完整代码如下:

#include <stdio.h>
int main(){
    int data[101], right[101];
    int i, n, t, len;
    scanf("%d", &n);
    for (i = 1; i <= n;i++)
        scanf("%d", &data[i]);
    len = n;
    for (i = 1; i <= n;i++){
        if(i!=n)
            right[i] = i + 1;
            else
                right[i] = 0;
    }
    len++;
    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];
    }
    getchar();
    getchar();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值