【C++系列】 算法与数据结构 day02 队列,链表
in C/C++ with 0 comment

【C++系列】 算法与数据结构 day02 队列,链表

in C/C++ with 0 comment

1 基于顺序表的队列

1.1 问题

队列是一种特殊的线性表,是限定在线性表表尾进行插入操作,而在线性表表头进行删除的线性表。由队列的概念衍生出几个子概念,它们是队首:允许进行删除的一端,又称为队头,用队首指针(front)来指示要删除的元素;队尾:允许进行插入的一端,用队尾指针(rear)来指示要插入元素的位置;空队,队列中没有元素时称为空队列。
顺序队是采用顺序存储结构的队,即使用一组连续的存储单元(一般使用数组)来模拟队,依次存放队中的数据元素。

  • 顺序队中存在一个“假溢出”的现象,“假溢出”是指随着入队、出队的进行,使整个队列在数组中整体向后移动,队尾指针已经移到了数组的最后一个元素,再有元素入队就会出现溢出,而事实上,此时队列中并未真的“满员”的现象,因为出队会使位置空出,所以数组的前部仍然有空间。
  • 为充分利用数组空间,克服“假溢出”现象,将队列分配的向量空间看成为一个首尾相接的圆环,并称这种队列为循环队列。

方案

顺序队的基本操作包括:

步骤

实现此案例需要按照如下步骤进行。

步骤一:定义队

在C语言中:
1)定义一个一维数组data,来表示队的顺序存储空间。
2)定义一个变量front,来存储队首的位置。
3)定义一个变量rear,来存储队尾的位置。
4)这三方面的信息共同描述一个队,可将它们封装在一起。

代码如下:

typedef int DataType;
struct Queue2 {
DataType data[6];
int front; //队首指针
int rear; //队尾指针
};

上述代码中,以下代码:
typedef int DataType;

是将数据类型int起了一个别名叫做DataType,并在后面的程序中只使用DataType,而不使用int。这样做的好处是当队列中的数据类型发生变化时,只需要修改此句中的int为要改变的数据类型,即可将程序中所有数据变量的数据类型变成指定的类型。

步骤二:初始化操作

在主程序中,定义队结构体的变量。
在初始化函数中将该变量中的队首、队尾指针初始化为0,表示为空队。
代码如下:

void init(struct Queue2 *q)
{
q->front = q->rear = 0;
}
int main(int argc, const char * argv[])
{
Queue2 q2;
init(&q2);
}

步骤三:判断队空

判断队空实际上是判断队首指针与队尾指针是否相同,当队首指针与队尾指针相同时,代表队中没有数据元素。
代码如下:

bool empty(struct Queue2 *q) {
return q->rear - q->front == 0;
}

步骤四:入队

代码如下:

bool push(struct Queue2 *q, DataType d) {
if (q->rear - q->front == 6) return false;
q->data[q->rear++ % 6] = d;
return true;
}

上述代码中,以下代码:
if (q->rear - q->front == 6) return false;
是判断队是否满,当队尾指针与队首指针的差值为6时,则表示队已经满了。6是步骤一定义队时定义的队容量。
上述代码中,以下代码:
q->data[q->rear++ % 6] = d;
是将入队元素d放置在队尾指针指向的位置。其中q->rear++ % 6是形成循环队列的关键,队尾指针对6求余数,则保证了数组q->data[]的下标永远在0~5之间变化,因为任何正整数对6求余数,余数只能是0~5,这样就保证数组不会越界访问,即防止了“假溢出”现象的出现。

步骤五:出队

bool pop(struct Queue2 *q) {
if (empty(q)) return false;
q->front++;
return true;
}

步骤六:取队首元素

DataType getFront(struct Queue2 *q) {
return q->data[q->front % 6];
}

上述代码中q->front % 6同样是形成循环队列的关键,队首指针对6求余数,则保证了数组q->data[]的下标永远在0~5之间变化,因为任何正整数对6求余数,余数只能是0~5,这样就保证数组不会越界访问,即防止了“假溢出”现象的出现。

1.4 完整代码

本案例的完整代码如下所示:
//循环队列
#include <stdio.h>
#include <stdbool.h>
typedef int DataType;
struct Queue2 {
DataType data[6];
int front; //开始位置
int rear; //结束位置
};
void init(struct Queue2 *q)
{
q->front = q->rear = 0;
}
bool empty(struct Queue2 *q) {
return q->rear - q->front == 0;
}
bool push(struct Queue2 *q, DataType d) {
if (q->rear - q->front == 6) return false;
q->data[q->rear++ % 6] = d;
return true;
}
bool pop(struct Queue2 *q) {
if (empty(q)) return false;
q->front++;
return true;
}
DataType getFront(struct Queue2 *q) {
return q->data[q->front % 6];
}
int main() {
struct Queue2 q2;
init(&q2);
for (int i = 0; i < 6; i++) {
push(&q2, i);
}
pop(&q2);
push(&q2, 300);
pop(&q2);
pop(&q2);
push(&q2, 200);
while (!empty(&q2)) {
printf("%d ", getFront(&q2));
pop(&q2);
}
printf("\n");
return 0;
}

基于链式表的队列

问题

链队是采用链式存储结构的队,即使用一组不要求连续的存储空间来模拟队。每个队元素为一个节点, 每个节点中包含两个域,一个是数据域,用于存储队元素的数据;另一个是指针域,用于存储下一个队元素的地址。

方案

链队的基本操作包括:

步骤

实现此案例需要按照如下步骤进行。

步骤一:定义队元素节点

在C语言中:

typedef int DataType;
struct Queue {
DataType data;
struct Queue *next;
};

上述代码中,以下代码:
struct Queue *next;
是定义了一个指向下一个队元素的指针,由于下一个队元素的数据类型与当前队元素的数据类型相同,所以指针的数据类型就是队节点的指针数据类型。

步骤二:初始化操作

在主程序中,定义队头、队尾指针。
在初始化函数中将队头、队尾指针初始化为NULL,表示为空栈。
代码如下:

void init(struct Queue** front, struct Queue** rear)
{
*front = NULL;
*rear = NULL;
}
int main()
{
struct Queue *front, *rear;
init(&front, &rear);
return 0;
}

上述代码中,以下代码:
void init(struct Queue** front, struct Queue** rear)
定义了初始化函数的函数头,该函数有两个形参,都是队元素结构体指针的指针。之所以使用指针的指针,是因为队头、队尾指针在函数执行过程中会被置空,而这种变化需要带回主函数。

步骤三:判断队空

判断队空操作实际上就是判断队头或队尾是否为空。
代码如下所示:

bool empty(struct Queue* node)
{
return node == NULL;
}

步骤四:入队

入队操作实际上就是在队中加入一个数据元素,对于链队,入队操作本质上就是在队中加入一个结点。
代码如下所示:

void push(struct Queue** front, struct Queue** rear, DataType d)
{
struct Queue *newNode = (struct Queue*)malloc(sizeof(struct Queue));
newNode->data = d;
newNode->next = NULL;
if (*rear != NULL)
(*rear)->next = newNode;
*rear = newNode;
if (*front == NULL)
*front = *rear;
}

上述代码中,以下代码:
void push(struct Queue** front, struct Queue** rear, DataType d)
定义了入队函数的函数头,该函数有三个形参,前两个是队结构的指针的指针,在这里使用指针的指针,还是因为需要将队头、队尾指针的变化带回主函数。第三个形参是需要入栈的数据。
上述代码中,以下代码:
struct Queue *newNode = (struct Queue*)malloc(sizeof(struct Queue));
是构造一个新的队元素节点。
上述代码中,以下代码:
newNode->data = d;
newNode->next = NULL;
是将需要入队的元素放入新的队元素节点中。
上述代码中,以下代码:

(*rear)->next = newNode;
*rear = newNode;

首先判断队尾指针是否为空,如果不为空,则将新创建的队元素节点加入到队中原队尾元素的后面,成为新的队尾元素,并将队尾指针指向新创建的队元素节点。如果队尾指针为空,则表示此时队中没有元素,所以直接将队尾指针指向新创建的队元素节点即可。正是由于第三行代码,使队尾指针发生了变化,而这种变化需要带回到主程序,所以函数的第二个形参必须是指针的指针。

上述代码中,以下代码:
if (*front == NULL)
*front = *rear;
是判断队头指针是否为空,如果为空,则表示队中没有元素,此时入队的元素为队中的唯一一个元素,所以此时队头、队尾指针均指向它。由于第二行代码,使队头指针发生了变化,而这种变化需要带回到主程序,所以函数的第一个形参必须是指针的指针。

步骤五:出队

出队操作实际上就是从队中删除队尾位置的元素,对于链队,出队操作本质上就是在队中删除一个结点。
代码如下所示:

void pop(struct Queue** front, struct Queue** rear)
{
if (empty(*rear))
return;
struct Queue *tempNode = *front;
*front = (*front)->next;
free(tempNode);
if (*front == NULL)
*rear = NULL;
}

上述代码中,以下代码:
if (empty(*rear))
return;
是判断链队是否为空,如果队为空是不能从队中删除元素的。
上述代码中,以下代码:
struct Queue *tempNode = *front;
*front = (*front)->next;
free(tempNode);
首先用一个临时指针保存原队头指针指向的队元素地址,即出队元素的地址,然后将队头指针指向下一个元素,这样队中就减少了一个元素。最后释放临时指针指向的元素,即释放出队元素所占的存储空间。
上述代码中,以下代码:
if (*front == NULL)
*rear = NULL;
是判断删除一个队元素后,队是否为空,如果队中没有元素了,也应该将队尾指针置为空,否则队尾指针将是野指针。

步骤六:取队首元素

取队首元素实际上就是将队头元素的值返回,对于链队,本质上是将队头节点的数据返回。注意,在取队首元素时,首先要判断队是否为空,空队是没有数据元素的。
代码如下:

void topData(struct Queue* front, DataType* data)
{
if (empty(front))
return;
*data = front->data;
}

2.4 完整代码

本案例的完整代码如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int DataType;
struct Queue {
DataType data;
struct Queue *next;
};
void init(struct Queue** front, struct Queue** rear)
{
*front = NULL;
*rear = NULL;
}
bool empty(struct Queue* node)
{
return node == NULL;
}
void push(struct Queue** front, struct Queue** rear, DataType d)
{
struct Queue *newNode = (struct Queue*)malloc(sizeof(struct Queue));
newNode->data = d;
newNode->next = NULL;
if (*rear != NULL)
(*rear)->next = newNode;
*rear = newNode;
if (*front == NULL)
*front = *rear;
}
void pop(struct Queue** front, struct Queue** rear)
{
if (empty(*rear))
return;
struct Queue *tempNode = *front;
*front = (*front)->next;
free(tempNode);
if (*front == NULL)
*rear = NULL;
}
void topData(struct Queue* front, DataType* data)
{
if (empty(front))
return;
*data = front->data;
}
int main()
{
struct Queue *front, *rear;
init(&front, &rear);
push(&front, &rear, 30);
push(&front, &rear, 60);
push(&front, &rear, 80);
while (!empty(front)) {
int data;
topData(front, &data);
printf("%d ", data);
pop(&front, &rear);
}
printf("\n");
return 0;
}

双向线性链表

问题

双向线性链表是采用链式存储的方式存储的线性表。链式存储结构是由一系列结点(链表中每一个元素称为结点)组成,每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储当前结点的前驱结点和后继结点地址的指针域,结点是在有数据时动态生成的,是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

方案

双向线性链表的基本操作包括:

步骤

实现此案例需要按照如下步骤进行。

步骤一:定义双向线性链表

在C语言中:

typedef int DataType;
struct Node{
DataType data;
struct Node *pre, *next;
};

上述代码中,以下代码:
typedef int DataType;
是将数据类型int起了一个别名叫做DataType,并在后面的程序中只使用DataType,而不使用int。这样做的好处是当双向线性链表中的数据类型发生变化时,只需要修改此句中的int为要改变的数据类型,即可将程序中所有数据变量的数据类型变成指定的类型。
上述代码中,以下代码:
struct Node *pre, *next;
分别定义了当前结点的前驱指针和后继指针。因为当前结点的前驱结点和后继结点都是双向线性链表的结点数据类型,所以前驱指针和后继指针也是struct Node *类型。

步骤二:初始化操作

在主程序中,定义双向线性链表的头指针。
在初始化函数中将头指针初始化为NULL,表示为空表。
代码如下所示:

void init(struct Node** head)
{
*head = NULL;
}
int main()
{
//头指针
struct Node *headList;
init(&headList);
}

步骤三:求表长

求表长即求双向线性链表中结点的个数,结点的个数是通过遍历链表并统计结点个数得到的。
代码如下所示:

int getSize(struct Node* head)
{
struct Node* p = head;
int count = 0;
while(p)
{
count ++;
p = p->next;
}
return count;
}

步骤四:取链表中指定位置的数据元素

首先,判断要查找的是否为头结点。
然后,遍历链表,确定要查找的结点位置。
代码如下:

struct Node* getptr(struct Node* head, int pos) {
struct Node *p = head;
if (p == 0 || pos == 0) {
return head;
}
for(int i = 0; p && i < pos; i++) {
p = p->next;
}
return p;
}

步骤五:插入结点

首先,判断要插入的结点位置是否正确。
然后,创建结点。
最后,插入结点,插入时分两种情况处理:一种是插入到第一个结点前面,另一种是插入到链表中间。

//指定位置 插入元素
bool insert(struct Node** head, int position, DataType d) {
if (position < 0 || position > getSize(*head)) {
3return false;
}

//创建 节点
struct Node *node = (struct Node*)malloc(sizeof(struct Node));
node->data = d;
node->pre = NULL;
node->next = NULL;
//插入到第一个节点的前面
if (position == 0) {
node->next = *head;
if (*head != NULL)
(*head)->pre = node;
*head = node;
return true;
}
//插入到链表的中间
struct Node *p = getptr(*head, position - 1);
struct Node* r = p->next;
node->next = r;
r->pre = node;
p->next = node;
node->pre = p;
return true;
}

上述代码中,以下代码:
if (*head != NULL)
(*head)->pre = node;
是判断头指针是否为空,如果不为空,则头指针指向的结点的前驱指针指向新加入的结点。
上述代码中,以下代码:
node->next = r;
r->pre = node;
p->next = node;
node->pre = p;
node为要插入的新结点,插入到p和r指向的结点之间,所以node的后继结点指针指向rr的前驱结点指针指向nodenode的前驱指针指向pp的后继指针指向node

步骤六:删除节点

首先,判断要删除的结点位置是否正确。
然后,删除结点,删除时分两种情况处理:一种是删除第一个结点,另一种是删除链表的中间结点。
最后,释放被删除结点所占有的存储空间。
代码如下:

//删除指定位置元素
bool erases(struct Node** head, int pos) {
if (pos < 0 || pos >= getSize(*head))
return false;
//删除第一个结点
struct Node *p = *head;
if (pos == 0) {
*head = (*head)->next;
if (*head != NULL)
(*head)->pre = NULL;
free(p);
p = NULL;
return true;
}
//删除链表的中间结点
p = getptr(*head, pos - 1);
struct Node *q = p->next;
p->next = q->next;
q->next->pre = p;
free(q);
q = NULL;
return true;
}

上述代码中,以下代码:
if (*head != NULL)
(*head)->pre = NULL;
是删除链表的头结点后,如果头指针不为空,即链表中还有结点,则让新的头结点的前驱指针为空。
上述代码中,以下代码:

p->next = q->next;
q->next->pre = p;

p指向要删除结点的前一结点,q指向要删除的结点,此时只需要让p由指向q,改为指向q的后继结点;让q的后继结点的前驱指针由指向q,改为指向p,即可将要删除的结点q从链表中断开,从而达到删除的目的。

步骤七:修改结点中数据

首先,判断要修改的结点是否在链表内。
然后,找到要修改的结点的位置。
最后,修改结点的数据。

//修改指定位置 元素
bool set(struct Node* head, int pos, DataType d) {
if (pos < 0 || pos >= getSize(head)) {
return false;
}
struct Node *p = getptr(head, pos);
p->data = d;
return true;
}

步骤八:删除链表

首先,遍历整个链表。
然后,逐个释放链表中每个结点。

void clears(struct Node* head) {
while (head) {
struct Node *p = head->next;
free(head);
head = p;
}
}

3.4 完整代码

本案例的完整代码如下所示:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
typedef int DataType;
struct Node{
DataType data;
struct Node *pre, *next;
};
void init(struct Node** head)
{
*head = NULL;
}
int getSize(struct Node* head)
{
struct Node* p = head;
int count = 0;
while(p)
{
count ++;
p = p->next;
}
return count;
}
//找到指定位置 元素地址
struct Node* getptr(struct Node* head, int pos) {
struct Node *p = head;
if (p == 0 || pos == 0) {
return head;
}
for(int i = 0; p && i < pos; i++) {
p = p->next;
}
return p;
}
//指定位置 插入元素
bool insert(struct Node** head, int position, DataType d) {
if (position < 0 || position > getSize(*head)) {
return false;
}
//创建 节点
struct Node *node = (struct Node*)malloc(sizeof(struct Node));
node->data = d;
node->pre = NULL;
node->next = NULL;
//插入到第一个节点的前面
if (position == 0) {
node->next = *head;
if (*head != NULL)
(*head)->pre = node;
*head = node;
return true;
}
//插入到链表的中间
struct Node *p = getptr(*head, position - 1);
struct Node* r = p->next;
node->next = r;
r->pre = node;
p->next = node;
node->pre = p;
return true;
}
//删除指定位置元素
bool erases(struct Node** head, int pos) {
if (pos < 0 || pos >= getSize(*head))
return false;
//删除第一个结点
struct Node *p = *head;
if (pos == 0) {
*head = (*head)->next;
if (*head != NULL)
(*head)->pre = NULL;
free(p);
p = NULL;
return true;
}
//删除链表的中间结点
p = getptr(*head, pos - 1);
struct Node *q = p->next;
p->next = q->next;
q->next->pre = p;
free(q);
q = NULL;
return true;
}
//修改指定位置 元素
bool set(struct Node* head, int pos, DataType d) {
if (pos < 0 || pos >= getSize(head)) {
return false;
}
struct Node *p = getptr(head, pos);
p->data = d;
return true;
}
//清理 链表
void clears(struct Node* head) {
while (head) {
struct Node *p = head->next;
free(head);
head = p;
}
}
//打印
void print(struct Node* head) {
struct Node *p = head;
while (p) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int main()
{
//头指针
struct Node *headList;
init(&headList);
insert(&headList, 0, 10);
insert(&headList, 0, 20);
insert(&headList, 0, 30);
insert(&headList, 2, 40);
insert(&headList, 2, 50);
insert(&headList, 0, 60);
insert(&headList, 0, 80);
print(headList);
erases(&headList, 1);
print(headList);
set(headList, 0, 100);
set(headList, 0, 110);
print(headList);
return 0;
}

单向线性链表

问题

单向线性链表是采用链式存储的方式存储的线性表。链式存储结构是由一系列结点(链表中每一个元素称为结点)组成,每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域,结点是在有数据时动态生成的,是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

方案

链表的基本操作包括:

实现此案例需要按照如下步骤进行。

步骤一:定义单向线性链表

在C语言中:

typedef int DataType;
struct Node{
DataType data;
struct Node *next;
};

上述代码中,以下代码:
typedef int DataType;
是将数据类型int起了一个别名叫做DataType,并在后面的程序中只使用DataType,而不使用int。这样做的好处是当链表中的数据类型发生变化时,只需要修改此句中的int为要改变的数据类型,即可将程序中所有数据变量的数据类型变成指定的类型。
步骤二:初始化操作

在主程序中,定义链表的头指针。
在初始化函数中将头指针初始化为NULL,表示为空表。
代码如下所示:

void init(struct Node** head)
{
*head = NULL;
}
int main()
{
//头指针
struct Node *headList;
init(&headList);
}

步骤三:求表长

求表长即求链表中结点的个数,结点的个数是通过遍历链表并统计结点个数得到的。
代码如下所示:

int getSize(struct Node* head)
{
struct Node* p = head;
int count = 0;
while(p)
{
count ++;
p = p->next;
}
return count;
}

步骤四:取链表中指定位置的数据元素

首先,判断要查找的是否为头结点。
然后,遍历链表,确定要查找的结点位置。
代码如下:

struct Node* getptr(struct Node* head, int pos) {
struct Node *p = head;
if (p == 0 || pos == 0) {
return head;
}
for(int i = 0; p && i < pos; i++) {
p = p->next;
}
return p;
}

步骤五:插入结点

首先,判断要插入的结点位置是否正确。
然后,创建结点。
最后,插入结点,插入时分两种情况处理:一种是插入到第一个结点前面,另一种是插入到链表中间。

bool insert(struct Node** head, int position, DataType d) {
if (position < 0 || position > getSize(*head)) {
return false;
}
//创建 节点
struct Node *node = (struct Node*)malloc(sizeof(struct Node));
node->data = d;
node->next = NULL;
//插入到第一个节点的前面
if (position == 0) {
node->next = *head;
*head = node;
return true;
}
//插入到链表的中间
struct Node *p = getptr(*head, position - 1);
struct Node* r = p->next;
node->next = r;
p->next = node;
return true;
}

步骤六:删除节点

首先,判断要删除的结点位置是否正确。
然后,删除结点,删除时分两种情况处理:一种是删除第一个结点,另一种是删除链表的中间结点。
最后,释放被删除结点所占有的存储空间。
代码如下:

bool erases(struct Node** head, int pos) {
if (pos < 0 || pos >= getSize(*head))
return false;
struct Node *p = *head;
if (pos == 0) {
*head = (*head)->next;
free(p);
p = NULL;
return true;
}
p = getptr(*head, pos - 1);
struct Node *q = p->next;
p->next = q->next;
free(q);
q = NULL;
return true;
}

步骤七:修改结点中数据

首先,判断要修改的结点是否在链表内。
然后,找到要修改的结点的位置。
最后,修改结点的数据。

bool set(struct Node* head, int pos, DataType d) {
if (pos < 0 || pos >= getSize(head)) {
return false;
}
struct Node *p = getptr(head, pos);
p->data = d;
return true;
}

步骤八:删除链表

首先,遍历整个链表。
然后,逐个释放链表中每个结点。

void clears(struct Node* head) {
while (head) {
struct Node *p = head->next;
free(head);
head = p;
}
}

3 完整代码

本案例的完整代码如下所示:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
typedef int DataType;
struct Node{
DataType data;
struct Node *next;
};
void init(struct Node** head)
{
*head = NULL;
}
int getSize(struct Node* head)
{
struct Node* p = head;
int count = 0;
while(p)
{
count ++;
p = p->next;
}
return count;
}
//找到指定位置 元素地址
struct Node* getptr(struct Node* head, int pos) {
struct Node *p = head;
if (p == 0 || pos == 0) {
return head;
}
for(int i = 0; p && i < pos; i++) {
p = p->next;
}
return p;
}
//指定位置 插入元素
bool insert(struct Node** head, int position, DataType d) {
if (position < 0 || position > getSize(*head)) {
return false;
}
//创建 节点
struct Node *node = (struct Node*)malloc(sizeof(struct Node));
node->data = d;
node->next = NULL;
//插入到第一个节点的前面
if (position == 0) {
node->next = *head;
*head = node;
return true;
}
//插入到链表的中间
struct Node *p = getptr(*head, position - 1);
struct Node* r = p->next;
node->next = r;
p->next = node;
return true;
}
//删除指定位置元素
bool erases(struct Node** head, int pos) {
if (pos < 0 || pos >= getSize(*head))
return false;
struct Node *p = *head;
if (pos == 0) {
*head = (*head)->next;
free(p);
p = NULL;
return true;
}
p = getptr(*head, pos - 1);
struct Node *q = p->next;
p->next = q->next;
free(q);
q = NULL;
return true;
}
//修改指定位置 元素
bool set(struct Node* head, int pos, DataType d) {
if (pos < 0 || pos >= getSize(head)) {
return false;
}
struct Node *p = getptr(head, pos);
p->data = d;
return true;
}
//清理 链表
void clears(struct Node* head) {
while (head) {
struct Node *p = head->next;
free(head);
head = p;
}
}
//打印
void print(struct Node* head) {
struct Node *p = head;
while (p) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int main()
{
//头指针
struct Node *headList;
init(&headList);
insert(&headList, 0, 10);
insert(&headList, 0, 20);
insert(&headList, 0, 30);
insert(&headList, 2, 40);
insert(&headList, 2, 50);
insert(&headList, 0, 60);
insert(&headList, 0, 80);
print(headList);
erases(&headList, 0);
print(headList);
set(headList, 0, 100);
set(headList, 0, 110);
print(headList);
return 0;
}
Responses