赞
踩
使用C语言实现单链表,单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。
在链表类中实现这些功能:
get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点
首先要确定是否设置头节点,本题使用头节点。我一直对头节点和头指针这两个东西很迷,这几天我再单独写篇文章来和大家交流一下。
单链表的节点包括数据域和指针域,代码如下:
- /**
- * 构造节点
- */
- typedef struct
- {
- int val; //数据域,存储有我们需要使用的数据
- struct MylinkedList *next; //指针域,存储有指向下一个节点的指针
- } MyLinkedList;
1、myLinkedListCreate():构造函数,初始化链表
众所周知,我们使用头结点来代表整个列表。下面的obj就是头节点,可以代替整个链表。
- /**
- * 构造一个有头结点的空链表
- */
- MyLinkedList *myLinkedListCreate()
- {
- MyLinkedList *obj = (MyLinkedList *)malloc(sizeof(MyLinkedList)); //在内存空间中开辟一块和节点数据结构大小一样的内存空间,构造头节点
- obj->next = NULL; //头节点的指针域置空
- return obj;
- }
2、myLinkedListGet(MyLinkedList *obj, int index),获取链表中第 index 个节点的值。如果索引无效,则返回-1
链表中第0个节点指的是头节点后面那一个,其他的以此类推。注意index取负数、链表为空、index大于链表节点数的情况
- /**
- * 获取链表中第 index 个节点的值。如果索引无效,则返回-1
- */
- int myLinkedListGet(MyLinkedList *obj, int index)
- {
- int counter = 0; //计数器
- int value = 0;
- MyLinkedList *p = obj->next; //定义一个指针,并指向头节点的下一个节点,即第0个节点
- while (p && counter < index) //当P存在而且没有遍历到第index节点时继续移动指针,直到counter=index时跳出循环;若P为空也会跳出循环,此时counter不一定等于index
- {
- p = p->next;
- counter++;
- }
- if (!p || counter > index) //跳出while循环后counter<=index,若P为空说明查询节点的index大于链表节点数,返回-1;若用户输入的index是一个负数,虽然P不为空,但这种情况应该返回-1
- {
- return -1;
- }
- else
- {
- value = p->val;
- return value;
- }
- }
3、myLinkedListAddAtHead(MyLinkedList *obj, int val):头插法的实现,就是在头节点和第0个节点间插入一个新节点
- /**
- * 头插法的实现
- * 在头节点和第0个节点间插入一个新节点
- */
- void myLinkedListAddAtHead(MyLinkedList *obj, int val)
- {
- MyLinkedList *p = obj; //将头节点赋值给指针P
- MyLinkedList *head = (MyLinkedList *)malloc(sizeof(MyLinkedList)); //新建一个节点
- head->val = val; //给新节点数据域赋值
- head->next = p->next; //让新节点指向头节点的下一个节点
- p->next = head; //让头节点指向新节点完成插入
- }
4、myLinkedListAddAtTail(MyLinkedList *obj, int val): 尾插法的实现,在链表最后的节点后再插入新的节点
- /**
- * 尾插法的实现
- * 在链表最后的节点后再插入新的节点
- */
- void myLinkedListAddAtTail(MyLinkedList *obj, int val)
- {
- MyLinkedList *tail = (MyLinkedList *)malloc(sizeof(MyLinkedList));
- tail->val = val;
- tail->next = NULL; //初始化新节点,指针域需要置空
- MyLinkedList *node = obj;
- while (node->next) //从头节点开始遍历链表,当节点的指针域为空时跳出循环,表明找到链表尾节点
- {
- node = node->next;
- }
- node->next = tail; //新节点成为尾节点
- }
5、myLinkedListAddAtIndex(MyLinkedList *obj, int index, int val):在第index节点前插入新节点,若index为负数则插入到链表头部,若index超出链表长度则不插入;这里也要注意链表为空,index越界、index为负数的情况。
- /**
- * 在第index节点前插入新节点,若index为负数则插入到链表头部,若index超出链表长度则不插入
- */
- void myLinkedListAddAtIndex(MyLinkedList *obj, int index, int val)
- {
- MyLinkedList *insertedNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
- insertedNode->val = val;
- MyLinkedList *node = obj;
- int counter = 0;
- if (index < counter) // index为负数时插入到链表头部
- {
- insertedNode->next = node->next;
- node->next = insertedNode;
- }
- while (node && counter < index) //counter等于index时,node的下标应该是index -1,这里和myLinkedListGet方法不同。差别在于当counter是0时,本方法node是头节点,但在myLinkedListGet方法中P是第0个节点
- {
- node = node->next;
- counter++;
- }
- if (!node || counter > index)
- {
- return -1;
- }
- insertedNode->next = node->next;
- node->next = insertedNode;
- }
6、myLinkedListDeleteAtIndex(MyLinkedList *obj, int index):若index有效的话则删除第index个节点,注意index为负数、链表为空的情况
- /**
- * 若index有效的话则删除第index个节点
- * 删除不同于插入。插入时,涉及第index、index-1两个节点,若第index-1个节点是尾节点,虽然第index个节点不存在,但是依然能插入;
- * 删除时,涉及第index-1、index、index+1三个节点,如果第index-1个节点为尾节点,则第index+1个节点即下面的temNode->next不存在,不能完成指针的赋值
- * 所以在判断循环时,判断条件是 node->next,这样才能保证第index+1个节点即下面的temNode->next存在(特殊条件就是为NULL)
- */
- void myLinkedListDeleteAtIndex(MyLinkedList *obj, int index)
- {
- MyLinkedList *node = obj;
- int counter = 0;
- while (node->next && counter < index) //找到第index-1 个节点,但需要保证第index+1个节点即下面的temNode->next存在(特殊条件就是为NULL)
- {
- node = node->next;
- counter++;
- }
- if (!(node->next) || counter > index)
- {
- return -1;
- }
- else
- {
- MyLinkedList *temNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
- temNode = node->next;
- node->next = temNode->next;
- free(temNode);
- }
- }
7、myLinkedListFree(MyLinkedList *obj):整表删除,从头节点开始删除
- /**
- * 整表删除
- */
- void myLinkedListFree(MyLinkedList *obj)
- {
- MyLinkedList *node = obj->next; //这里node指向的是头节点的下一个节点,与前面有所不同。整表删除时要将头节点以外的所有节点删除,保留头节点
- MyLinkedList *temNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
- while (node) //判断除当前结点是否为空,不为空时删除此节点
- {
- temNode = node->next; //删除时要保留被删除节点的下一个节点
- free(node);
- node = temNode;
- }
- obj->next = NULL;
- }
8、主函数: 大家可以自己试一试,看看结果对不对。
- int main()
- {
- MyLinkedList *obj = myLinkedListCreate();
-
- int param_1 = myLinkedListGet(obj, 0);
- printf("%d\n", param_1);
-
- myLinkedListAddAtHead(obj, 0);
- int param_2 = myLinkedListGet(obj, 0);
- printf("%d\n", param_2);
-
- myLinkedListAddAtTail(obj, 1);
- int param_3 = myLinkedListGet(obj, 0);
- printf("%d\n", param_3);
-
- myLinkedListAddAtIndex(obj, 1, 2);
- int param_4 = myLinkedListGet(obj, 1);
- printf("%d\n", param_4);
-
- myLinkedListDeleteAtIndex(obj, 2); //02
-
- myLinkedListFree(obj);
- int param_5 = myLinkedListGet(obj, 0);
- printf("%d\n", param_5);
- }
- #include <stdio.h>
- #include <stdlib.h>
-
- /**
- * 构造节点
- */
- typedef struct
- {
- int val; //数据域,存储有我们需要使用的数据
- struct MylinkedList *next; //指针域,存储有指向下一个节点的指针
- } MyLinkedList;
-
- /**
- * 构造一个有头结点的空链表
- */
- MyLinkedList *myLinkedListCreate()
- {
- MyLinkedList *obj = (MyLinkedList *)malloc(sizeof(MyLinkedList)); //在内存空间中开辟一块和节点数据结构大小一样的内存空间,构造头节点
- obj->next = NULL; //头节点的指针域置空
- return obj;
- }
-
- /**
- * 获取链表中第 index 个节点的值。如果索引无效,则返回-1
- */
- int myLinkedListGet(MyLinkedList *obj, int index)
- {
- int counter = 0; //计数器
- int value = 0;
- MyLinkedList *p = obj->next; //定义一个指针,并指向头节点的下一个节点,即第0个节点
- while (p && counter < index) //当P存在而且没有遍历到第index节点时继续移动指针,直到counter=index时跳出循环;若P为空也会跳出循环,此时counter不一定等于index
- {
- p = p->next;
- counter++;
- }
- if (!p || counter > index) //跳出while循环后counter<=index,若P为空说明查询节点的index大于链表节点数,返回-1;若用户输入的index是一个负数,虽然P不为空,但这种情况应该返回-1
- {
- return -1;
- }
- else
- {
- value = p->val;
- return value;
- }
- }
-
- /**
- * 头插法的实现
- * 在头节点和第0个节点间插入一个新节点
- */
- void myLinkedListAddAtHead(MyLinkedList *obj, int val)
- {
- MyLinkedList *p = obj; //将头节点赋值给指针P
- MyLinkedList *head = (MyLinkedList *)malloc(sizeof(MyLinkedList)); //新建一个节点
- head->val = val; //给新节点数据域赋值
- head->next = p->next; //让新节点指向头节点的下一个节点
- p->next = head; //让头节点指向新节点完成插入
- }
-
- /**
- * 尾插法的实现
- * 在链表最后的节点后再插入新的节点
- */
- void myLinkedListAddAtTail(MyLinkedList *obj, int val)
- {
- MyLinkedList *tail = (MyLinkedList *)malloc(sizeof(MyLinkedList));
- tail->val = val;
- tail->next = NULL; //初始化新节点,指针域需要置空
- MyLinkedList *node = obj;
- while (node->next) //从头节点开始遍历链表,当节点的指针域为空时跳出循环,表明找到链表尾节点
- {
- node = node->next;
- }
- node->next = tail; //新节点成为尾节点
- }
-
- /**
- * 在第index节点前插入新节点,若index为负数则插入到链表头部,若index超出链表长度则不插入
- */
- void myLinkedListAddAtIndex(MyLinkedList *obj, int index, int val)
- {
- MyLinkedList *insertedNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
- insertedNode->val = val;
- MyLinkedList *node = obj;
- int counter = 0;
- if (index < counter) // index为负数时插入到链表头部
- {
- insertedNode->next = node->next;
- node->next = insertedNode;
- }
- while (node && counter < index) //counter等于index时,node的下标应该是index -1,这里和myLinkedListGet方法不同。差别在于当counter是0时,本方法node是头节点,但在myLinkedListGet方法中P是第0个节点
- {
- node = node->next;
- counter++;
- }
- if (!node || counter > index)
- {
- return -1;
- }
- insertedNode->next = node->next;
- node->next = insertedNode;
- }
-
- /**
- * 若index有效的话则删除第index个节点
- * 删除不同于插入。插入时,涉及第index、index-1两个节点,若第index-1个节点是尾节点,虽然第index个节点不存在,但是依然能插入;
- * 删除时,涉及第index-1、index、index+1三个节点,如果第index-1个节点为尾节点,则第index+1个节点即下面的temNode->next不存在,不能完成指针的赋值
- * 所以在判断循环时,判断条件是 node->next,这样才能保证第index+1个节点即下面的temNode->next存在(特殊条件就是为NULL)
- */
- void myLinkedListDeleteAtIndex(MyLinkedList *obj, int index)
- {
- MyLinkedList *node = obj;
- int counter = 0;
- while (node->next && counter < index) //找到第index-1 个节点,但需要保证第index+1个节点即下面的temNode->next存在(特殊条件就是为NULL)
- {
- node = node->next;
- counter++;
- }
- if (!(node->next) || counter > index)
- {
- return -1;
- }
- else
- {
- MyLinkedList *temNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
- temNode = node->next;
- node->next = temNode->next;
- free(temNode);
- }
- }
-
- /**
- * 整表删除
- */
- void myLinkedListFree(MyLinkedList *obj)
- {
- MyLinkedList *node = obj->next; //这里node指向的是头节点的下一个节点,与前面有所不同。整表删除时要将头节点以外的所有节点删除,保留头节点
- MyLinkedList *temNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
- while (node) //判断除当前结点是否为空,不为空时删除此节点
- {
- temNode = node->next; //删除时要保留被删除节点的下一个节点
- free(node);
- node = temNode;
- }
- obj->next = NULL;
- }
-
- /**
- * Your MyLinkedList struct will be instantiated and called as such:
- * MyLinkedList* obj = myLinkedListCreate();
- * int param_1 = myLinkedListGet(obj, index);
-
- * myLinkedListAddAtHead(obj, val);
-
- * myLinkedListAddAtTail(obj, val);
-
- * myLinkedListAddAtIndex(obj, index, val);
-
- * myLinkedListDeleteAtIndex(obj, index);
-
- * myLinkedListFree(obj);
- */
- int main()
- {
- MyLinkedList *obj = myLinkedListCreate();
-
- int param_1 = myLinkedListGet(obj, 0);
- printf("%d\n", param_1); //-1
-
- myLinkedListAddAtHead(obj, 0);
- int param_2 = myLinkedListGet(obj, 0);
- printf("%d\n", param_2); //0
-
- myLinkedListAddAtTail(obj, 1); // 0 1
- int param_3 = myLinkedListGet(obj, 0);
- printf("%d\n", param_3); //0
-
- myLinkedListAddAtIndex(obj, 1, 2); //021
- int param_4 = myLinkedListGet(obj, 1);
- printf("%d\n", param_4); //2
-
- myLinkedListDeleteAtIndex(obj, 2); //02
-
- myLinkedListFree(obj);
- int param_5 = myLinkedListGet(obj, 0);
- printf("%d\n", param_5); //-1
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。