顺序表的链式存储结构
#include <stdio.h> #include <stdlib.h> #include <time.h> //如果需要良好的封装的话就需要两个结构 typedef struct ListNode { int data; struct ListNode* next; }; typedef struct LinkList { ListNode* head; int length; }; ListNode* init_listnode(int val) { ListNode* p = (ListNode*)malloc(sizeof(ListNode)); p->data = val; p->next = NULL; return p; } LinkList* init_linklist() { LinkList* l = (LinkList*)malloc(sizeof(LinkList)); l->head->next = NULL; //虚拟头节点的话,如果往后面第二个位置插入,就往后移动几个 l->length = 0; return l; } void clear_listnode(ListNode* node) { if (node == NULL) return; //如果链表的数据域也是malloc出来的,也要free数据域 free(node); return; } void clear_linklist(LinkList* l) { if (l == NULL) { return; } ListNode* p = l->head->next, * q; while (p) { //销毁的同时要有一个q来储存删除结点的后面一个结点 q = p->next; clear_listnode(p);//删除相应的结点 p = q;//这就走到了下一个结点 } free(l); return; } int insert(LinkList* l, int ind, int val) { if (l == NULL) return 0; if (ind<0 || ind>l->length) { return 0; } ListNode* p = l->head,*node = init_listnode (val); while (ind--) { p = p->next; } node->next = p->next; p->next = node; l->length++; return; } int erase(LinkList* l, int ind) { if (l == NULL) return 0 ; if (ind < 0 && ind >= l->length) return 0; //后面就开始删除结点了 ListNode* p = l->head, *q; while (ind--) { p = p->next; } //现在p就指向了待删除结点的前一个位置 q = p->next->next; clear_listnode(p->next); p->next = q; l->length--; return 1; } void OutPut(LinkList* l) { printf("LinkList(%d) : ", l->length); for (ListNode* p = l->head->next; p; p = p->next) { printf("%d -> ", p->data); } printf("NULL\n"); return; } //上面是链表的相关定义 int main() { LinkList* l = init_linklist(); srand(time(0)); for (int i = 0; i <30 ; i++) { int op = rand() % 4; int ind = rand() % (l->length + 1); int val = rand() % 100; switch (op) { case 0: case 1: case 2: { printf("insert %d at %d to LinkList %d\n", val, ind, insert(l, ind, val)); }break; case 3: { printf("erase item at %d from LinkList = %d\n", ind, erase(l, ind)); }break; } OutPut(l); } }
这个与mooc陈越上面的链式表还是有很大的不同的。这个版本的封装程度大了很多。而且对链表进行了两次封装。个人觉得这种的更好。整体封装程度更高,也更好理解。做一个积累。如果只说说上面这个的话感觉太水了一点,后面再补一个循环链表的内容。

发现了没,单向循环链表头指针中储存的是循环链表中的尾结点的地址。为什么要这样设置呢?
如果假设现在这个head指向1号结点的话,如果要往头插入结点的话,那就需要这个head指向头的前一个结点也就是6号结点。如果要完成这个操作的话不就要遍历一圈了。如果一开始就是指向6号结点的话,要往头插入结点就直接插入就好了,不需要再走一大圈了。
还有就是如果我要往第i个位置插入,只要让这个head指针往前走i步就可以插入了(这个时候停在i-1的位置)。这个和之前的虚拟头节点的用法其实是一样的。

浙公网安备 33010602011771号