c语言不用指针实现链表,静态链表(C语言, 数组,模拟无指针编程语言数组实现单链表)...

说明:

数据元素为结构体(复合数据类型):

存放游标和实际数据

数据的第1个元素和末尾元素存放元数据

**第1个元素**

游标:存放(指向)备用下标,供下次使用,初始化为1

数据:链表tail标识,(尾节点下标)

**末尾元素:**

游标:存放链表第1个有效节点下标, head标识,初始化为1(根据len特殊处理)

数据:链表当前有效节点个数(长度len)

35eace6bd382e0651991b27a776225ec.png

#include

#include

#include

#include

#define MAXSIZE 10

typedef struct Node{

int data;

int cur;

} NODE, LINKLIST[MAXSIZE];

void init(LINKLIST);

bool is_full(LINKLIST);

bool is_empty(LINKLIST);

// 遍历所有有效元素

void traverse(LINKLIST);

// 遍历所有元素,便于学习

void traverse_all(LINKLIST);

// 追加节点(入栈)

bool append(LINKLIST, int);

// 获取指定位置上一个节点的下标,注意先检查再调用

int get_pre(LINKLIST, int);

// 删除指定节点,只返回成功失败,不返回删除成功的元素值

bool delete(LINKLIST, int);

// 允许前后插入

bool insert(LINKLIST, int, int);

/*

* 清空链表, 如没特殊要求, 也可用init函数代替

* 这里调用delete函数,并从链表尾向前删除节点(只清空不改变head指向)

*/

bool clear(LINKLIST);

// 获取指定节点, 假设数据范围为正整数,错误我们返回-1

int get(LINKLIST, int);

// 获取并删除尾节点(出栈), 假设数据范围取正整数,错误我们返回-1

int pop(LINKLIST);

int pop(LINKLIST L)

{

if (is_empty(L)) {

printf("pop error! linklist is empty.\n");

return -1;

}

int len = L[MAXSIZE-1].data;

int val = get(L, len);

delete(L, len);

printf("pop success! val: %d\n", val);

return val;

}

int get(LINKLIST L, int pos)

{

int len = L[MAXSIZE-1].data;

if (pos < 1 || pos > len) {

printf("get error! pos(%d) out of range.\n", pos);

return -1;

}

if (pos == 1) {

int head = L[MAXSIZE-1].cur;

int val = L[head].data;

printf("get success! val:%d\n", val);

return val;

}

int pre = get_pre(L, pos);

int pos_index = L[pre].cur;

int val = L[pos_index].data;

printf("get success! val:%d\n", val);

return val;

}

bool clear(LINKLIST L)

{

if (is_empty(L)) {

printf("链表为空,无需clear操作.\n");

return true;

}

int len = L[MAXSIZE-1].data;

for (int i=len; i > 0; i--) {

if (! delete(L, i))

return false;

}

return true;

}

bool insert(LINKLIST L, int pos, int e)

{

int len = L[MAXSIZE-1].data;

int head = L[MAXSIZE-1].cur;

int tail = L[0].data;

int now_index = L[0].cur;

int next_index = L[now_index].cur;

if (is_full(L)) {

printf("插入失败,链表已满!\n");

return false;

}

if (pos < 1 || pos > len + 1) {

printf("插入失败,无效的插入位置: %d\n", pos);

return false;

}

int pre = get_pre(L, pos);

printf("尝试插入位置 %d 值 %d", pos, e);

// 插入空链表的第1个节点(条件成立时一定是pos=1)

if (is_empty(L)) {

printf(", (节点类型: 空链表第1个节点)");

NODE New = {e, 0};

L[now_index] = New;

L[0].cur = next_index;

L[0].data = now_index;

++L[MAXSIZE-1].data;

L[MAXSIZE-1].cur = now_index;

}

// 插入新头节点

else if (pos == 1) {

printf(", (节点类型: 新头节点)");

NODE New = {e, head};

L[now_index] = New;

// head 指向新头节点

L[MAXSIZE-1].cur = now_index;

// 备用节点指向

L[0].cur = next_index;

++L[MAXSIZE-1].data;

}

// 插入新尾节点

else if (pos == len + 1){

printf(", (节点类型: 新尾节点)");

NODE New = {e, 0};

L[now_index] = New;

// 上一个节点(前尾节点)由原来的0指向新的tail节点

L[pre].cur = now_index;

L[0].cur = next_index;

// 更新tail标识

L[0].data = now_index;

++L[MAXSIZE-1].data;

}

//插入中间节点

else {

printf(", (节点类型: 中间节点)");

int this_next = L[pre].cur;

// 连接后继节点

NODE New = {e, this_next};

L[now_index] = New;

// 连接前躯节点

L[pre].cur = now_index;

L[0].cur = next_index;

++L[MAXSIZE-1].data;

}

putchar('\n');

return true;

}

bool delete(LINKLIST L, int pos)

{

/*删除任意节点共用操作:

* len减1

* 回收空间

*删除不同类型节点需要做的额外操作:

* pos == 1 的情况:头节点非尾节点,或头节点同时为尾节点

* 无需再查找删除位置的前躯节点下标

* 更新链表head, tail标识

* pos > 1的情况:尾节点, 或中间节点

* 删除尾节点:pos == len

* 查找前躯节点下标

* 前躯节点的游标改为0

* 更新链表tail标识为前躯节点

* 删除中间节点:

* 查找前躯节点下标

* 连接前躯节点及后继节点

*

*/

printf("尝试删除位置: %d, ", pos);

if (is_empty(L)) {

printf("删除失败, 链表为空!\n");

return false;

}

int head = L[MAXSIZE-1].cur;

int tail = L[0].data;

if (pos < 1 || pos > MAXSIZE-2) {

printf("删除失败, 位置超出范围\n");

return false;

}

else if (pos == 1) {

int new_head = L[head].cur;

// 被删除节点数据置0

L[head].data = 0;

// 判断头节点是否同时为尾节点

if (new_head == 0) {

printf("(节点类型:头节点 + 尾节点)");

// tail指向0(head不变,下次追加元素从这个开始追加)

L[0].data = 0;

}

else {

printf("(节点类型:头节点)");

L[MAXSIZE-1].cur = new_head;

}

// 回收空间

L[head].cur = L[0].cur;

L[0].cur = head;

}

else {

int pre = get_pre(L, pos);

// 删除的位置等于长度则为尾节点

if (pos == L[MAXSIZE-1].data) {

// 被删除节点数据置0

L[tail].data = 0;

printf("(节点类型:尾节点)");

// 更新tail指向

L[0].data = pre;

// 上一个节点变为尾节点,更新游标

L[pre].cur = 0;

// 回收空间

L[tail].cur = L[0].cur;

L[0].cur = tail;

}

else {

printf("(节点类型:中间节点)");

// 连接前躯和后继

int now_index = L[pre].cur;

L[pre].cur = L[now_index].cur;

// 被删除节点数据置0

L[now_index].data = 0;

// 回收空间

L[now_index].cur = L[0].cur;

L[0].cur = now_index;

}

}

--L[MAXSIZE-1].data;

printf(", 删除成功!\n");

return true;

}

// 函数不做复杂检查,无法找到时返回-1

int get_pre(LINKLIST L, int pos)

{

if (pos == 1)

return 0;

int p = L[MAXSIZE-1].cur;

int i = 1;

while (L[p].cur && i < pos-1) {

p = L[p].cur;

++i;

}

return p;

}

bool append(LINKLIST L, int e)

{

printf("追加元素:%d\n", e);

if (is_full(L)) {

printf("追加失败,链表已满!\n");

return false;

}

NODE New = {e, 0}; //追加的尾元素固定指向0

int tail_index = L[0].data; //获取链表尾元素的下标

int now_index = L[0].cur; //本次追加元素使用的下标

int next_index = L[now_index].cur; //保存备用下标的下一个下标作为新备用下标

L[now_index] = New;

++L[MAXSIZE-1].data; //len(当前有效元素)加1

L[0].data = now_index; //更新链表tail标识

L[0].cur = next_index; //更新链表备用下标

// 非init后首次插入,需要tail元素连接新元素操作

if (tail_index != 0)

L[tail_index].cur = now_index;

return true;

}

bool is_empty(LINKLIST L)

{

if (L[MAXSIZE-1].data == 0)

return true;

return false;

}

bool is_full(LINKLIST L)

{

if (L[MAXSIZE-1].data == MAXSIZE-2)

return true;

return false;

}

void traverse(LINKLIST L)

{

if (is_empty(L)) {

printf("链表为空!\n");

return;

}

printf("链表元素:");

// 保存链表的头元素下标(并不总是1)

int head = L[MAXSIZE-1].cur;

// 当head == 0 代表有效节点遍历结束

while (head != 0) {

printf("%d ", L[head].data);

head = L[head].cur;

}

putchar('\n');

}

void traverse_all(LINKLIST L)

{

printf("--------------current linklist state-----------------\n");

printf("%10s", "Cursor: ");

for (int i=0; i

printf("%4d ", L[i].cur);

}

putchar('\n');

printf("%10s", "Data: ");

for (int i=0; i

printf("%4d ", L[i].data);

}

putchar('\n');

printf("%10s", "index: ");

for (int i=0; i

printf("%4d ", i);

}

putchar('\n');

}

void init(LINKLIST L)

{

for (int i=0; i

L[i].cur = i + 1;

L[i].data = 0;

}

/*

* 数组的尾元素的游标初始化指向第1个有数据的元素下标

* 虽然此时1并不是是有效元素,但是append追加元素不用再加判断为空修改head变量了

*/

L[MAXSIZE-1].cur = 1; //head

L[MAXSIZE-1].data = 0; //len

}

int main(void)

{

LINKLIST L;

init(L);

// test append

traverse(L);

traverse_all(L);

append(L, 11);

traverse_all(L);

append(L, 12);

traverse_all(L);

append(L, 13);

append(L, 14);

append(L, 15);

append(L, 16);

append(L, 17);

append(L, 18);

traverse_all(L);

append(L, 19);

traverse_all(L);

traverse(L);

// test delete

delete(L, 9);

delete(L, 0);

delete(L, 1);

traverse_all(L);

delete(L, 7);

traverse_all(L);

delete(L, 4);

traverse_all(L);

delete(L, 2);

traverse_all(L);

delete(L, 2);

traverse_all(L);

delete(L, 3);

traverse_all(L);

delete(L, 1);

traverse_all(L);

delete(L, 1);

traverse_all(L);

delete(L, 1);

traverse(L);

// test append

append(L, 21);

traverse_all(L);

append(L, 22);

traverse_all(L);

append(L, 23);

append(L, 24);

append(L, 25);

append(L, 26);

append(L, 27);

append(L, 28);

traverse_all(L);

append(L, 29);

traverse_all(L);

traverse(L);

// test clear

clear(L);

traverse_all(L);

traverse(L);

clear(L);

// test insert

insert(L, 0, 100);

insert(L, 2, 101);

insert(L, 1, 32);

traverse_all(L);

traverse(L);

insert(L, 1, 31);

traverse_all(L);

traverse(L);

insert(L, 3, 33);

traverse_all(L);

traverse(L);

insert(L, 4, 34);

traverse_all(L);

traverse(L);

insert(L, 5, 35);

traverse_all(L);

traverse(L);

insert(L, 5, 355);

traverse_all(L);

traverse(L);

insert(L, 4, 344);

traverse_all(L);

traverse(L);

insert(L, 3, 333);

traverse_all(L);

traverse(L);

insert(L, 2, 322);

traverse_all(L);

traverse(L);

// test pop

get(L, 9);

get(L, 0);

get(L, 8);

get(L, 1);

// test pop

pop(L);

traverse_all(L);

traverse(L);

pop(L);

traverse_all(L);

traverse(L);

pop(L);

traverse_all(L);

traverse(L);

pop(L);

traverse_all(L);

traverse(L);

pop(L);

pop(L);

traverse_all(L);

traverse(L);

pop(L);

pop(L);

pop(L);

traverse_all(L);

traverse(L);

return 0;

}

output

链表为空!

--------------current linklist state-----------------

Cursor: 1 2 3 4 5 6 7 8 9 1

Data: 0 0 0 0 0 0 0 0 0 0

index: 0 1 2 3 4 5 6 7 8 9

追加元素:11

--------------current linklist state-----------------

Cursor: 2 0 3 4 5 6 7 8 9 1

Data: 1 11 0 0 0 0 0 0 0 1

index: 0 1 2 3 4 5 6 7 8 9

追加元素:12

--------------current linklist state-----------------

Cursor: 3 2 0 4 5 6 7 8 9 1

Data: 2 11 12 0 0 0 0 0 0 2

index: 0 1 2 3 4 5 6 7 8 9

追加元素:13

追加元素:14

追加元素:15

追加元素:16

追加元素:17

追加元素:18

--------------current linklist state-----------------

Cursor: 9 2 3 4 5 6 7 8 0 1

Data: 8 11 12 13 14 15 16 17 18 8

index: 0 1 2 3 4 5 6 7 8 9

追加元素:19

追加失败,链表已满!

--------------current linklist state-----------------

Cursor: 9 2 3 4 5 6 7 8 0 1

Data: 8 11 12 13 14 15 16 17 18 8

index: 0 1 2 3 4 5 6 7 8 9

链表元素:11 12 13 14 15 16 17 18

尝试删除位置: 9, 删除失败, 位置超出范围

尝试删除位置: 0, 删除失败, 位置超出范围

尝试删除位置: 1, (节点类型:头节点), 删除成功!

--------------current linklist state-----------------

Cursor: 1 9 3 4 5 6 7 8 0 2

Data: 8 0 12 13 14 15 16 17 18 7

index: 0 1 2 3 4 5 6 7 8 9

尝试删除位置: 7, (节点类型:尾节点), 删除成功!

--------------current linklist state-----------------

Cursor: 8 9 3 4 5 6 7 0 1 2

Data: 7 0 12 13 14 15 16 17 0 6

index: 0 1 2 3 4 5 6 7 8 9

尝试删除位置: 4, (节点类型:中间节点), 删除成功!

--------------current linklist state-----------------

Cursor: 5 9 3 4 6 8 7 0 1 2

Data: 7 0 12 13 14 0 16 17 0 5

index: 0 1 2 3 4 5 6 7 8 9

尝试删除位置: 2, (节点类型:中间节点), 删除成功!

--------------current linklist state-----------------

Cursor: 3 9 4 5 6 8 7 0 1 2

Data: 7 0 12 0 14 0 16 17 0 4

index: 0 1 2 3 4 5 6 7 8 9

尝试删除位置: 2, (节点类型:中间节点), 删除成功!

--------------current linklist state-----------------

Cursor: 4 9 6 5 3 8 7 0 1 2

Data: 7 0 12 0 0 0 16 17 0 3

index: 0 1 2 3 4 5 6 7 8 9

尝试删除位置: 3, (节点类型:尾节点), 删除成功!

--------------current linklist state-----------------

Cursor: 7 9 6 5 3 8 0 4 1 2

Data: 6 0 12 0 0 0 16 0 0 2

index: 0 1 2 3 4 5 6 7 8 9

尝试删除位置: 1, (节点类型:头节点), 删除成功!

--------------current linklist state-----------------

Cursor: 2 9 7 5 3 8 0 4 1 6

Data: 6 0 0 0 0 0 16 0 0 1

index: 0 1 2 3 4 5 6 7 8 9

尝试删除位置: 1, (节点类型:头节点 + 尾节点), 删除成功!

--------------current linklist state-----------------

Cursor: 6 9 7 5 3 8 2 4 1 6

Data: 0 0 0 0 0 0 0 0 0 0

index: 0 1 2 3 4 5 6 7 8 9

尝试删除位置: 1, 删除失败, 链表为空!

链表为空!

追加元素:21

--------------current linklist state-----------------

Cursor: 2 9 7 5 3 8 0 4 1 6

Data: 6 0 0 0 0 0 21 0 0 1

index: 0 1 2 3 4 5 6 7 8 9

追加元素:22

--------------current linklist state-----------------

Cursor: 7 9 0 5 3 8 2 4 1 6

Data: 2 0 22 0 0 0 21 0 0 2

index: 0 1 2 3 4 5 6 7 8 9

追加元素:23

追加元素:24

追加元素:25

追加元素:26

追加元素:27

追加元素:28

--------------current linklist state-----------------

Cursor: 9 0 7 5 3 8 2 4 1 6

Data: 1 28 22 25 24 26 21 23 27 8

index: 0 1 2 3 4 5 6 7 8 9

追加元素:29

追加失败,链表已满!

--------------current linklist state-----------------

Cursor: 9 0 7 5 3 8 2 4 1 6

Data: 1 28 22 25 24 26 21 23 27 8

index: 0 1 2 3 4 5 6 7 8 9

链表元素:21 22 23 24 25 26 27 28

尝试删除位置: 8, (节点类型:尾节点), 删除成功!

尝试删除位置: 7, (节点类型:尾节点), 删除成功!

尝试删除位置: 6, (节点类型:尾节点), 删除成功!

尝试删除位置: 5, (节点类型:尾节点), 删除成功!

尝试删除位置: 4, (节点类型:尾节点), 删除成功!

尝试删除位置: 3, (节点类型:尾节点), 删除成功!

尝试删除位置: 2, (节点类型:尾节点), 删除成功!

尝试删除位置: 1, (节点类型:头节点 + 尾节点), 删除成功!

--------------current linklist state-----------------

Cursor: 6 9 7 5 3 8 2 4 1 6

Data: 0 0 0 0 0 0 0 0 0 0

index: 0 1 2 3 4 5 6 7 8 9

链表为空!

链表为空,无需clear操作.

插入失败,无效的插入位置: 0

插入失败,无效的插入位置: 2

尝试插入位置 1 值 32, (节点类型: 空链表第1个节点)

--------------current linklist state-----------------

Cursor: 2 9 7 5 3 8 0 4 1 6

Data: 6 0 0 0 0 0 32 0 0 1

index: 0 1 2 3 4 5 6 7 8 9

链表元素:32

尝试插入位置 1 值 31, (节点类型: 新头节点)

--------------current linklist state-----------------

Cursor: 7 9 6 5 3 8 0 4 1 2

Data: 6 0 31 0 0 0 32 0 0 2

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32

尝试插入位置 3 值 33, (节点类型: 新尾节点)

--------------current linklist state-----------------

Cursor: 4 9 6 5 3 8 7 0 1 2

Data: 7 0 31 0 0 0 32 33 0 3

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32 33

尝试插入位置 4 值 34, (节点类型: 新尾节点)

--------------current linklist state-----------------

Cursor: 3 9 6 5 0 8 7 4 1 2

Data: 4 0 31 0 34 0 32 33 0 4

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32 33 34

尝试插入位置 5 值 35, (节点类型: 新尾节点)

--------------current linklist state-----------------

Cursor: 5 9 6 0 3 8 7 4 1 2

Data: 3 0 31 35 34 0 32 33 0 5

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32 33 34 35

尝试插入位置 5 值 355, (节点类型: 中间节点)

--------------current linklist state-----------------

Cursor: 8 9 6 0 5 3 7 4 1 2

Data: 3 0 31 35 34 355 32 33 0 6

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32 33 34 355 35

尝试插入位置 4 值 344, (节点类型: 中间节点)

--------------current linklist state-----------------

Cursor: 1 9 6 0 5 3 7 8 4 2

Data: 3 0 31 35 34 355 32 33 344 7

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32 33 344 34 355 35

尝试插入位置 3 值 333, (节点类型: 中间节点)

--------------current linklist state-----------------

Cursor: 9 7 6 0 5 3 1 8 4 2

Data: 3 333 31 35 34 355 32 33 344 8

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32 333 33 344 34 355 35

插入失败,链表已满!

--------------current linklist state-----------------

Cursor: 9 7 6 0 5 3 1 8 4 2

Data: 3 333 31 35 34 355 32 33 344 8

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32 333 33 344 34 355 35

get error! pos(9) out of range.

get error! pos(0) out of range.

get success! val:35

get success! val:31

get success! val:35

尝试删除位置: 8, (节点类型:尾节点), 删除成功!

pop success! val: 35

--------------current linklist state-----------------

Cursor: 3 7 6 9 5 0 1 8 4 2

Data: 5 333 31 0 34 355 32 33 344 7

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32 333 33 344 34 355

get success! val:355

尝试删除位置: 7, (节点类型:尾节点), 删除成功!

pop success! val: 355

--------------current linklist state-----------------

Cursor: 5 7 6 9 0 3 1 8 4 2

Data: 4 333 31 0 34 0 32 33 344 6

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32 333 33 344 34

get success! val:34

尝试删除位置: 6, (节点类型:尾节点), 删除成功!

pop success! val: 34

--------------current linklist state-----------------

Cursor: 4 7 6 9 5 3 1 8 0 2

Data: 8 333 31 0 0 0 32 33 344 5

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32 333 33 344

get success! val:344

尝试删除位置: 5, (节点类型:尾节点), 删除成功!

pop success! val: 344

--------------current linklist state-----------------

Cursor: 8 7 6 9 5 3 1 0 4 2

Data: 7 333 31 0 0 0 32 33 0 4

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32 333 33

get success! val:33

尝试删除位置: 4, (节点类型:尾节点), 删除成功!

pop success! val: 33

get success! val:333

尝试删除位置: 3, (节点类型:尾节点), 删除成功!

pop success! val: 333

--------------current linklist state-----------------

Cursor: 1 7 6 9 5 3 0 8 4 2

Data: 6 0 31 0 0 0 32 0 0 2

index: 0 1 2 3 4 5 6 7 8 9

链表元素:31 32

get success! val:32

尝试删除位置: 2, (节点类型:尾节点), 删除成功!

pop success! val: 32

get success! val:31

尝试删除位置: 1, (节点类型:头节点 + 尾节点), 删除成功!

pop success! val: 31

pop error! linklist is empty.

--------------current linklist state-----------------

Cursor: 2 7 6 9 5 3 1 8 4 2

Data: 0 0 0 0 0 0 0 0 0 0

index: 0 1 2 3 4 5 6 7 8 9

链表为空!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值