每日一题
设计单链表
要求
题目要我们实现有关单链表的基本操作,即以下几个函数:
MyLinkedList* myLinkedListCreate() //创建单链表 int myLinkedListGet(MyLinkedList* obj, int index) //得到下标为index的节点的值,如果index无效则返回-1 void myLinkedListAddAtHead(MyLinkedList* obj, int val) //链表头插 void myLinkedListAddAtTail(MyLinkedList* obj, int val) //链表尾插 void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) //在下标index处插入值为val的节点,如果index等于链表长度,则相当于尾插 void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) //删除下标为index的节点,如果index无效,则不操作 void myLinkedListFree(MyLinkedList* obj) //删除链表
解析函数形参
- 我们知道,单链表有带哨兵位(头一个节点为无效节点)和不带哨兵位(第一个节点就存储有效数据)两种形式,而二者在用法上的主要区别,就是在对头结点的处理上
- 例如,如果我们要删除链表第一个有效节点,若我们的链表有哨兵位,那就好办,直接让哨兵位链接到第二个节点即可,但如果我们的链表没有哨兵位呢?那操作就不是删除第一个节点然后返回第二个节点这么简单了,因为我们知道,函数的形参只是实参的一份临时拷贝,对形参的修改不会影响实参,也就是说,在函数中删除我们的第一个节点,实际上实参的头节点仍然存在,因此如果想要对无哨兵位的链表进行头删操作,就要传入头节点的二级指针,这样才能达到要求。
- 我们看到题目所给的函数形参传入的是一级指针,因此显然,我们要使用带哨兵位的链表。
实现代码
typedef struct List {
int val;
struct List *next;
} MyLinkedList;
//初始化单链表
MyLinkedList* myLinkedListCreate() {
MyLinkedList *head = (MyLinkedList *)malloc(sizeof(MyLinkedList));
head->next = NULL;
return head;
}
//得到下标为index的节点的值,如果index无效则返回-1
int myLinkedListGet(MyLinkedList* obj, int index) {
MyLinkedList *cur = obj->next; //第一个节点不存储有效数据,因此从后一个节点开始计数
int count = 0;
while(cur)
{
if(count == index)
return cur->val;
cur = cur->next;
count++;
}
return -1;
}
//头插
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
//创建新节点
MyLinkedList *newHead = (MyLinkedList*)malloc(sizeof(MyLinkedList));
newHead->val = val;
newHead->next = NULL;
//如果链表为空
if(obj->next == NULL)
obj->next = newHead;
//如果链表不为空
else
{
newHead->next = obj->next;
obj->next = newHead;
}
}
//尾插
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
//创建尾节点
MyLinkedList *newHead = (MyLinkedList*)malloc(sizeof(MyLinkedList));
newHead->val = val;
newHead->next = NULL;
//找到链表的尾
MyLinkedList *cur = obj;
while(cur->next)
cur = cur->next;
//实现插入
cur->next = newHead;
}
//在下标index处插入值为val的节点,如果index等于链表长度,则相当于尾插
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
//如果index为0,相当于头插
if(index == 0)
{
myLinkedListAddAtHead(obj,val);
return;
}
MyLinkedList *newHead = (MyLinkedList*)malloc(sizeof(MyLinkedList)); //新建节点
//第一个节点不存储有效数据,因此从后一个节点开始计数,同时定义一个指针记录cur的前一个节点便于插入
MyLinkedList *cur = obj->next, *pre = obj;
newHead->val = val;
int count = 0;
while(cur)
{
//如果index大于0小于链表长度
if(count == index && cur != NULL)
{
pre->next = newHead;
newHead->next = cur;
return;
}
pre = cur;
cur = cur->next;
count++;
}
//如果index等于链表长度,直接尾插
if(count == index && cur == NULL)
{
myLinkedListAddAtTail(obj,val);
return;
}
//index不合法,直接return
return;
}
//删除下标为index的节点,如果index无效,则不操作
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
//第一个节点不存储有效数据,因此从后一个节点开始计数,同时定义一个指针记录cur的前一个节点便于删除
MyLinkedList *cur = obj->next, *pre = obj;
int count = 0;
while(cur)
{
if(count == index)
{
pre->next = cur->next;
free(cur);
return;
}
pre = cur;
cur = cur->next;
count++;
}
return;
}
//销毁链表
void myLinkedListFree(MyLinkedList* obj) {
MyLinkedList *cur = obj->next;
while(cur)
{
MyLinkedList *temp = cur->next; //定义temp记录cur的下一个位置
free(cur);
cur = temp;
}
}