左耳听风第三周
每周完成一个ARTS: 每周至少做一个 leetcode 的算法题、阅读并点评至少一篇英文技术文章、学习至少一个技术技巧、分享一篇有观点和思考的技术文章。(也就是 Algorithm、Review、Tip、Share 简称ARTS)
Algorithm
- 设计链表 设计链表 解题语言 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 大于链表长度,则不会插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
示例:
MyLinkedList linkedList = new MyLinkedList();
linkedList.addAtHead(1);
linkedList.addAtTail(3);
linkedList.addAtIndex(1,2); //链表变为1-> 2-> 3
linkedList.get(1); //返回2
linkedList.deleteAtIndex(1); //现在链表是1-> 3
linkedList.get(1); //返回3
提示:
所有值都在 [1, 1000] 之内。
操作次数将在 [1, 1000] 之内。
请不要使用内置的 LinkedList 库。
/* 创建结构体 */
struct node
{
int val;
struct node *next;
};
typedef struct {
struct node * head;
struct node * tail;
int size;
} MyLinkedList;
/* 释放内存 */
void free_list(struct node *head)
{
struct node *prev;
while (head)
{
prev = head; //用一个中间量来存储当前结点 , 而 head 继续用于指向下一结点
head = head->next;
free(prev); //释放内存
}
}
/* 创建结点 */
struct node *make_node(int val , struct node *next)
{
struct node *ml = malloc(sizeof(*ml)); // 分配内存给结点 ml
//assert(ml);
ml->val = val;
ml->next = next;
return ml;
}
/** Initialize your data structure here. */
MyLinkedList* myLinkedListCreate() {
MyLinkedList *ml =calloc(1,sizeof(*ml));//calloc 会将所有成员初始化为 0
return ml;
}
/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
int myLinkedListGet(MyLinkedList* obj, int index) {
if (index >= obj->size)
return -1;//超出索引则返回 -1
struct node * cur = obj->head;//定义头节点开始遍历指针
for (int i = 0; i < index; ++i) {
cur = cur->next;// 题目定义的链表索引从 0 开始
}
return cur->val;
}
/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
struct node *newnode = make_node(val,obj->head);
obj->head = newnode;//链表头结点指向加入结点
obj->size += 1;//链表长度 +1
if (obj->size==1)
{
obj->tail = obj->head;// 当只有一个结点时, 头结点就是尾结点
}
}
/** Append a node of value val to the last element of the linked list. */
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
struct node *newnode = make_node(val,NULL);
if (obj->tail!=NULL)// 当尾结点不为空时 , 即链表不为空时 , 尾结点就是 新增结点 , 链表数量+1
{
obj->tail->next = newnode;
obj->tail = newnode;
obj->size += 1;
}
else
{
myLinkedListAddAtHead(obj,val);
}
}
/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
if (index > obj->size) return;
if (index == obj->size) {
return myLinkedListAddAtTail(obj, val);
}
if (index == 0) {
return myLinkedListAddAtHead(obj, val);
}
struct node * cur = obj->head;
for (int i = 1; i < index; ++i) {
cur = cur->next;
}
struct node * newnode = make_node(val, cur->next);
cur->next = newnode;
obj->size += 1;
}
/** Delete the index-th node in the linked list, if the index is valid. */
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
if (index >= obj->size) return;
struct node * temp, * rm;
if (index == 0) {
temp = obj->head;
obj->head = temp->next;
free(temp);
obj->size -= 1;
return;
}
if (index == obj->size - 1) {
temp = obj->head;
while (temp->next != obj->tail)
temp = temp->next;
free(temp->next);
obj->tail = temp;
obj->size -= 1;
return;
}
temp = obj->head;
for (int i = 1; i < index; ++i) {
temp = temp->next;
}
// Temp is now the node before the one we want to remove
rm = temp->next;
temp->next = rm->next;
free(rm);
obj->size -= 1;
}
void myLinkedListFree(MyLinkedList* obj) {
free_list(obj->head);
free(obj);
}
/**
* Your MyLinkedList struct will be instantiated and called as such:
* struct MyLinkedList* obj = myLinkedListCreate();
* int param_1 = myLinkedListGet(obj, index);
* myLinkedListAddAtHead(obj, val);
* myLinkedListAddAtTail(obj, val);
* myLinkedListAddAtIndex(obj, index, val);
* myLinkedListDeleteAtIndex(obj, index);
* myLinkedListFree(obj);
*/
这周刚学到链表 ,这道题对于链表的理解要求还是有一定难度的 代码的思想参考了 LeetCode 英文社区的答案,一部分还没有完全消化 , 后面会再复盘重写下。
Review
Things You Should Never Do, Part I
(英文版)文章
文章是 2004 / 04 /06 年写的 , 内容上来说有点老了
感悟:喜欢写新代码胜过看旧代码 , 这似乎是程序员的通病 。 但是对于大公司来说 , 完全舍弃旧的代码是一件非常不合格的事情 , 这也很有可能导致公司业务的崩溃。
旧的代码是经过很多年的沉淀的 , 所以很难出现 Bug 因为大部分常见的已经被修复了。 我们所看到的旧代码 都是很多年积累的 , 几个字符的改动可能是当年那批优秀的工程师 几个星期排查出的 Bug。
而新代码必定会在开始的 1 - 3 年出现各种无法预测的 Bug , 这时企业就该慎重考虑到底是要用新代码开发 , 还是继续维护旧代码呢 ?
作为程序员来说 , 对照旧代码的维护日志 , 明白一个旧代码出现过哪些问题又是如何解决的 , 这会让我们初学者有着很大提升 。
Tip
http://md.aclickall.com/
有了自己的微信公众号和博客 , 就该头疼该如何排版了 , 毕竟如果你自己都看不下去的东西 ,又怎么能指望别人来看呢 ?
Md2All 在线编辑器 , 支持文章 Markdown 排版 同时可以修改前端样式进行 DIY 美化 ,还完美支持复制到公众号文章 , 貌似图片还能避免被微信公众号压缩质量 , 好不好用一试便知
share
分享的是我这周学习 C 语言链表的一些笔记 , 虽然很简单 ,但是刚开始自己琢磨的时候确实很头疼 , 希望能给和我一样的初学者一些帮助 , 同时欢迎各位大佬给我提各方面的改进意见 。