链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
链表有很多种不同的类型:单向链表,双向链表以及循环链表。(以上参考维基百科)
本章主要讲解单向链表
1、插入
下面是链表的按序插入过程(以结点中key值的大小作为插入依据,递增排序)。
其实现的过程考虑三种情况:
1)L为空;
2)在链表的头部插入;
3)在链表的中间插入(包括在链表尾部插入的情况)。
2、删除
删除和插入是一个相反的过程,一般需要先找的删除结点的前驱(prev)。
1)删除链表的首结点(prev == NULL);
L = cur->next
2)删除链表的中间结点。
prev->next = cur->next
3、反转
对单链表进行反转操作,图(2)、(3)为反转的过程。
4、合并
将两个已排序的链表进行合并
/******************************************************** * 简单的单链表(无哑结点) *******************************************************/ #include <stdio.h> #include <stdlib.h> typedef struct lnode { int key; struct lnode *next; } LNode, *LIST; //============================================================= // 根据key值,获得该节点位置 //============================================================= static inline LNode *ListSearch(LIST l, int key) { LNode *p = l; while (p && p->key != key) p = p->next; return p; } //============================================================= // 获取x结点的前驱 //============================================================= static inline LNode *GetPrev(LIST l, LNode *x) { LNode *prev = l; while (prev && prev->next != x) prev = prev->next; return prev; } //============================================================= // 按序插入结点 //============================================================= LNode *ListInsert(LIST l, LNode *x) { if (l == NULL) // case 1 return x; if (x->key < l->key) { // case 2 x->next = l; l = x; } else { // case 3 // 获得x的前驱 LNode *prev = l; while (prev->next && prev->next->key <= x->key) prev = prev->next; x->next = prev->next; prev->next = x; } return l; } //============================================================= // 删除结点,给出待删除结点的位置(指针) //============================================================= LIST ListDelete(LIST l, LNode *x) { if (l == NULL) return NULL; if (l == x) { // case 1 /*l->key == x->key*/ l = x->next; } else { // case 2 // 获得x的前驱 LNode *prev = l; while (prev->next && prev->next != x) // prev->next->key < x->key prev = prev->next; prev->next = x->next; } return l; } //============================================================= // 对指定的链表进行反转 //============================================================= LIST ListReverse(LIST l) { LNode *cur = l; // 当前结点 LNode *prev = NULL; LNode *next = NULL; while (cur) { next = cur->next; cur->next = prev; // 反转 prev = cur; // prve和cur往前移动。 cur = next; } return prev; } //============================================================= // 合并两个链表(増序) //============================================================= LIST ListMerge(LIST l1, LIST l2) { LNode *l = NULL; LNode **pos = &l; while (l1 && l2) { if (l1->key < l2->key) { *pos = l1; l1 = l1->next; } else { *pos = l2; l2 = l2->next; } pos = &(*pos)->next; // 注意,pos指向下一个结点的地址 } if (l1) *pos = l1; else *pos = l2; return l; } //============================================================= // 交换链表中两结点的位置 //============================================================= LIST ListSwap(LIST l, LNode *x, LNode *y) { if (l == NULL) return l; // 获取x、y的前驱 LNode *xprev = GetPrev(l, x); LNode *yprev = GetPrev(l, y); LNode *xnext = x->next; // 记录 x->next = y->next; // 相当于插入x if (yprev == NULL) // y为头结点 l = x; else yprev->next = x; y->next = xnext; // 相当于插入y if (xprev == NULL) // x为头结点 l = y; else xprev->next = y; // if (xprev == NULL) { // LNode *xnext = x->next; // x->next = y->next; // 相当于插入x // yprev->next = x; // y->next = xnext; // 相当于插入y // l = y; // } else if (yprev == NULL){ // LNode *ynext = y->next; // y->next =x->next; // xprev->next = y; // x->next = ynext; // l = x; // } else { // LNode *xnext = x->next; // x->next = y->next; // 相当于插入x // yprev->next = x; // y->next = xnext; // 相当于插入y // xprev->next = y; // } return l; } //============================================================= // 对指定的链表进行输出 //============================================================= void ListPrint(LIST l) { LNode *p = l; while (p) { printf("%d\t", p->key); p = p->next; } printf("\n"); } int main() { int arr[] = {34, 2, 53, 21, 354, 78}; int len = sizeof(arr) / sizeof(arr[0]); LIST l1 = NULL; LIST l2 = NULL; LIST l = NULL; printf("Insert:\n"); for (int i = 0; i < len; i++) { LNode *x = (LNode *)malloc(sizeof(LNode)); if (!x) { printf("x malloc error\n"); return -1; } x->key = arr[i]; x->next = NULL; l1 = ListInsert(l1, x); ListPrint(l1); LNode *y = GetPrev(l1, ListSearch(l1, arr[i])); if (y == NULL) printf("%d is not prev!\n", arr[i]); else printf("%d prev is %d\n", arr[i], y->key); } printf("Insert:\n"); for (int i = 0; i < len - 2; i++) { LNode *x = (LNode *)malloc(sizeof(LNode)); if (!x) { printf("x malloc error\n"); return -1; } x->key = arr[i] * 2 - 40; x->next = NULL; l2 = ListInsert(l2, x); ListPrint(l2); } printf("Merge:\n"); l = ListMerge(l1, l2); ListPrint(l); printf("Delete:\n"); l = ListDelete(l, ListSearch(l, -36)); ListPrint(l); printf("Reverse:\n"); l = ListReverse(l); ListPrint(l); printf("Swap():\n"); l = ListSwap(l, ListSearch(l, arr[1]), ListSearch(l, arr[4])); ListPrint(l); // printf("Delete:\n"); // for (int i = 0; i < len; i++) { // l = ListDelete(l, ListSearch(l, arr[i])); // ListPrint(l); // } LNode *y = GetPrev(l, ListSearch(l, 53)); printf("53 prev is %d\n", y->key); system("pause"); return 0; }