单链表优点:
- 可以动态增加和删除。
- 不需要定义初始大小。
点链表缺点:
- 不能随机访问。需要逐个遍历直到找到目标项。
- 用到动态内存分配和指针,代码复杂度提升,内存泄漏和内存段错误风险提升。
- 开销大较大,因为是动态分配内存。而且每项需要存储一个额外的指针。
定义单链表:
------------------------------ ------------------------------
| | | \ | | |
| val | next |--------------| val | next |
| | | / | | |
------------------------------ ------------------------------单链表的每一个节点包含两部分:数据val和指向下一个节点的指针next。
1 typedef struct list_node ListNode; 2 3 struct list_node{ 4 int val; 5 struct list_node* next; 6 };
初始化单链表:
关键在两个指针:newNode和curNode。
newNode是用来指向新建节点。而curNode则是指向链表尾节点。
如果head为NULL,那么head和curNode都将指向newNode。
如果head不为NULL,那么只需将尾节点的next指向newNode,即curNode->next=newNode;,同时需记录新链表的尾节点,即curNode=newNode;。
以此类推,直到数组的最后一个元素的值插入到链表的尾部。
1 ListNode* InitLinkedList(ListNode* head, int* array, int size) 2 { 3 head = NULL; 4 ListNode* newNode = NULL; 5 ListNode* curNode = NULL; 6 for (int i = 0; i < size; i++) 7 { 8 newNode = malloc(sizeof(ListNode)); 9 newNode->val = array[i]; 10 newNode->next = NULL; 11 12 if (head == NULL) 13 { 14 head = newNode; 15 curNode = newNode; 16 } 17 else 18 { 19 curNode->next = newNode; 20 curNode = newNode; 21 } 22 } 23 24 return head; 25 }
打印单链表:
1 void PrintLinkedList(ListNode* head) 2 { 3 while (head != NULL) 4 { 5 printf("%d ", head->val); 6 head = head->next; 7 } 8 printf("\n"); 9 }
反转单链表:
反转的关键在于借助于两个额外指针p和q。同时记录q的next节点。因为q的next节点需要指向p,如果不先记录q的next节点,链表会就此断开。
接下来就是p和q的逐步向前推进,直到q指向NULL,而此时p刚好是反转后的链表的头节点。
1 ListNode* ReverseLinkedList(ListNode* head) 2 { 3 ListNode* p = NULL; 4 ListNode* q = head; 5 6 while (q != NULL) 7 { 8 ListNode* nextq = q->next; 9 q->next = p; 10 p = q; 11 q = nextq; 12 } 13 14 return p; 15 }
主函数:
1 int main(void) 2 { 3 ListNode* root = NULL; 4 int numArray[] = { 1, 2, 3, 4, 5 }; 5 6 root = InitLinkedList(root, numArray, 5); 7 printf("original linked list:\n"); 8 PrintLinkedList(root); 9 10 root = ReverseLinkedList(root); 11 printf("reversed linked list:\n"); 12 PrintLinkedList(root); 13 14 getchar(); 15 return 0; 16 17 }
结果截图:
解题的要点在于有一个清晰的思路,然后就是将逻辑用代码来实现。
时间: 2024-12-09 10:08:02