赞
踩
目录
本章节紧跟上一篇文章《顺序表的实现》来继续讲述线性表的一种:单链表。
前面我们讲的线性表的顺序存储结构。它是有缺点的,最大的缺点就是插入和删除时需要移动大量元素,这显然就需要耗费时间。能不能想办法解决呢?
要解决这个问题,我们就得考虑一下导致这个问题的原因。为什么当插入和删除时,就要移动大量元素,仔细分析后,发现原因就在于相邻两元素的存储位置也具有邻居关系。它们编号是1,2,3,…,n,它们在内存中的位置也是挨着的,中间没有空隙,当然就无法快速介入,而删除后,当中就会留出空隙,自然需要弥补。问题就出在这里。
我们可以在第一个元素时,就知道第二个元素的位置(内存地址),而找到它;在第二个元素时,再找到第三个元素的位置(内存地址)。这样所有的元素我们就都可以通过遍历而找到,而这就是单链表的特点,如下图所示。
而链表的结构则如下图所示,第一个节点的指针由头节点所指,第二个节点的指针由第一个节点所指,以此类推。
定义一些功能常量和单链表的结构。
这里需要注意的是,我给链表起别名的是一个指针,后面我们在实现链表功能的时候,我们传递函数参数的时候要传递的是一个双指针(LinkList* L)。 这是因为链表的结构使然,因为链表存储的是其他链表的指针,它是一个地址,后面我们在进行链表的增加和删除的时候,会经常涉及到指针的变化。
如果函数的参数是本身一级指针,那么在函数内部对指针的修改将不会反映到函数外部,因为函数接收到的是指针的一个副本。使用指针的指针作为参数,则可以确保在函数内部对指针的修改能够反映到原始的指针上。
typedef struct Node* LinkList;
- #include <iostream>
-
- #define MAX_SIZE 20
- #define OK 1
- #define ERROR 0
- #define TRUE 1
- #define FALSE 0
- typedef int Status;
- typedef int ElemType;
-
- typedef struct Node
- {
- ElemType data;
- struct Node* next;
- }Node;
-
- typedef struct Node* LinkList;
链表的初始化主要是为头节点分配内存空间,使它的data 和 next 都指向为 NULL,方便我们后续的操作。
- Status InitList(LinkList* L)
- {
- *L = (LinkList)malloc(sizeof(Node));
- if (*L == NULL) return ERROR;
- (*L)->data = 0;
- (*L)->next = NULL;
- return OK;
- }
对链表进行清空操作,因为是用 malloc 进行分配的空间,对堆中的空间进行释放操作。
- Status ClearList(LinkList* L)
- {
- LinkList p, q;
-
- p = (*L)->next;
- while (p != NULL)
- {
- q = p->next;
- free(p);
- p = q;
- }
- (*L)->next = NULL;
- return OK;
- }
判断头节点指向的元素是否为空。即 next 是否为 NULL。
- Status isListEmpty(LinkList L)
- {
- if (L->next == NULL) return TRUE;
- return FALSE;
- }
求链表的长度,定义一个变量,然后用while循环遍历链表。
- int ListLength(LinkList L)
- {
- int num{ 0 };
- LinkList temp = L->next;
- while (temp != NULL)
- {
- temp = temp->next;
- num++;
- }
- return num;
- }
定义一个变量,进行while操作,判断是否与指定位置 i 相同,获取其节点值。
- Status GetElem(LinkList L, int i, ElemType* e)
- {
- int num{ 1 };
- LinkList temp = L->next;
- while (temp != NULL && num < i)
- {
- temp = temp->next;
- num++;
- }
- if (temp == NULL || num > i) return ERROR;
- *e = temp->data;
- }
和上述功能类似,返回值为 int 位置。
- int LocateElem(LinkList L, ElemType* e)
- {
- int num{ 0 };
- LinkList temp = L->next;
- while (temp != NULL)
- {
- num++;
- if (temp->data = *e)
- {
- return num;
- }
- temp = temp->next;
- }
- return 0;
- }
此功能为链表的难点所在,需要根据图像理解实现,如下图所示。
- Status LinkInsert(LinkList* L, int i, ElemType e)
- {
- int j;
- LinkList p, s;
- p = *L;
- j = 1;
-
- while (p != NULL && j < i)
- {
- p = p->next;
- ++j;
- }
- if (!p || j > i) return ERROR;
-
- s = (LinkList)malloc(sizeof(Node));
- if (s == NULL) return ERROR;
- s->data = e;
-
- s->next = p->next;
- p->next = s;
-
- return OK;
-
- }
和上功能类似,如图所示。
- Status LinkDelete(LinkList* L, int i, ElemType* e)
- {
- int j;
- LinkList p, s;
- j = 1;
- p = (*L);
- while (p != NULL && j < i)
- {
- p = p->next;
- ++j;
- }
- if (!p || j > i) return ERROR;
-
- s = p->next;
- p->next = s->next;
- *e = s->data;
- free(s);
- return OK;
- }
功能比较简单,通过不断遍历打印其节点的data值。
- Status visit(ElemType e)
- {
- printf("%d->", e);
- return OK;
- }
- Status ListTraverse(LinkList L)
- {
- LinkList p = L->next;
- while (p != NULL)
- {
- visit(p->data);
- p = p->next;
- }
- printf("\n");
- return OK;
- }
测试主要为测试以上的功能是否可以实现。
- int TestSingleList()
- {
- LinkList L;
- ElemType e;
- Status ret;
- int j, k;
- // 初始化
- ret = InitList(&L);
- printf("初始化长度:%d\n", ListLength(L));
-
- for(j = 1; j <= 5; j++)
- {
- ret = LinkInsert(&L, 1, j);
- }
- printf("插入5个元素后:");
- ListTraverse(L);
- ret = isListEmpty(L);
- printf("是否为空,%d\n", ret);
- ret = ClearList(&L);
- printf("清空后的长度:%d\n", ListLength(L));
- printf("是否为空,%d\n", ret);
- for (j = 1; j <= 10; j++)
- {
- ret = LinkInsert(&L, j, j);
- }
- printf("插入10个元素后:");
- ListTraverse(L);
-
- LinkInsert(&L, 3, 100);
- printf("在第2个节点后面增加元素100:");
- ListTraverse(L);
-
- LinkDelete(&L, 2, &e);
- printf("删除第二个节点,节点元素为%d :", e);
- ListTraverse(L);
-
- ClearList(&L);
-
- return 0;
- }
结果输出如图所示:
总代码如下:
-
-
- #include <iostream>
-
- #define MAX_SIZE 20
- #define OK 1
- #define ERROR 0
- #define TRUE 1
- #define FALSE 0
- typedef int Status;
- typedef int ElemType;
-
- typedef struct Node
- {
- ElemType data;
- struct Node* next;
- }Node;
-
- typedef struct Node* LinkList;
-
- Status visit(ElemType e)
- {
- printf("%d->", e);
- return OK;
- }
-
- Status InitList(LinkList* L)
- {
- *L = (LinkList)malloc(sizeof(Node));
- if (*L == NULL) return ERROR;
- (*L)->data = 0;
- (*L)->next = NULL;
- return OK;
- }
-
- Status ClearList(LinkList* L)
- {
- LinkList p, q;
-
- p = (*L)->next;
- while (p != NULL)
- {
- q = p->next;
- free(p);
- p = q;
- }
- (*L)->next = NULL;
- return OK;
- }
-
- Status isListEmpty(LinkList L)
- {
- if (L->next == NULL) return TRUE;
- return FALSE;
- }
-
-
- int ListLength(LinkList L)
- {
- int num{ 0 };
- LinkList temp = L->next;
- while (temp != NULL)
- {
- temp = temp->next;
- num++;
- }
- return num;
- }
-
- Status GetElem(LinkList L, int i, ElemType* e)
- {
- int num{ 1 };
- LinkList temp = L->next;
- while (temp != NULL && num < i)
- {
- temp = temp->next;
- num++;
- }
- if (temp == NULL || num > i) return ERROR;
- *e = temp->data;
- }
-
- int LocateElem(LinkList L, ElemType* e)
- {
- int num{ 0 };
- LinkList temp = L->next;
- while (temp != NULL)
- {
- num++;
- if (temp->data = *e)
- {
- return num;
- }
- temp = temp->next;
- }
- return 0;
- }
-
- Status LinkInsert(LinkList* L, int i, ElemType e)
- {
- int j;
- LinkList p, s;
- p = *L;
- j = 1;
-
- while (p != NULL && j < i)
- {
- p = p->next;
- ++j;
- }
- if (!p || j > i) return ERROR;
-
- s = (LinkList)malloc(sizeof(Node));
- if (s == NULL) return ERROR;
- s->data = e;
-
- s->next = p->next;
- p->next = s;
-
- return OK;
-
- }
-
- Status LinkDelete(LinkList* L, int i, ElemType* e)
- {
- int j;
- LinkList p, s;
- j = 1;
- p = (*L);
- while (p != NULL && j < i)
- {
- p = p->next;
- ++j;
- }
- if (!p || j > i) return ERROR;
-
- s = p->next;
- p->next = s->next;
- *e = s->data;
- free(s);
- return OK;
- }
-
- Status ListTraverse(LinkList L)
- {
- LinkList p = L->next;
- while (p != NULL)
- {
- visit(p->data);
- p = p->next;
- }
- printf("\n");
- return OK;
- }
-
- Status CreateListHead(LinkList* L,int n)
- {
- LinkList p;
- srand((unsigned)time(0));
- *L = (LinkList)malloc(sizeof(Node));
- if (*L == NULL) return ERROR;
- (*L)->next = NULL;
- for (int i = 0; i < n; i++)
- {
- p = (LinkList)malloc(sizeof(Node));
- if (p == NULL) return ERROR;
- p->data = rand() % 100 + 1;
- p->next = (*L)->next;
- (*L)->next = p;
- }
- return OK;
- }
-
- Status CreateListTail(LinkList* L,int n)
- {
- LinkList p, r;
- srand((unsigned)time(0));
- *L = (LinkList)malloc(sizeof(Node));
- if (*L == NULL) return ERROR;
- (*L)->next = NULL;
- r = (*L);
- for (int i = 0; i < n; i++)
- {
- p = (LinkList)malloc(sizeof(Node));
- if (p == NULL) return ERROR;
- p->data = rand() % 100 + 1;
- r->next = p;
- r = p;
- }
- return OK;
- }
-
-
-
-
-
-
-
- int TestSingleList()
- {
- LinkList L;
- ElemType e;
- Status ret;
- int j, k;
- // 初始化
- ret = InitList(&L);
- printf("初始化长度:%d\n", ListLength(L));
-
- for(j = 1; j <= 5; j++)
- {
- ret = LinkInsert(&L, 1, j);
- }
- printf("插入5个元素后:");
- ListTraverse(L);
- ret = isListEmpty(L);
- printf("是否为空,%d\n", ret);
- ret = ClearList(&L);
- printf("清空后的长度:%d\n", ListLength(L));
- printf("是否为空,%d\n", ret);
- for (j = 1; j <= 10; j++)
- {
- ret = LinkInsert(&L, j, j);
- }
- printf("插入10个元素后:");
- ListTraverse(L);
-
- LinkInsert(&L, 3, 100);
- printf("在第2个节点后面增加元素100:");
- ListTraverse(L);
-
- LinkDelete(&L, 2, &e);
- printf("删除第二个节点,节点元素为%d :", e);
- ListTraverse(L);
-
- ClearList(&L);
-
- return 0;
- }
-
- int main()
- {
- return TestSingleList();
- }
-
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。