线性表(1):链表
本专栏的记录,只适用于408的考试。其它考试请酌情参考。
本章应用题和算法题⛳都可能考,尤其是算法题。
ps: 由于408不太要求程序能编译或者是健壮性良好,因此文中代码可能会不能跑起来。
线性表
-
定义
零个或多个数据元素的有限序列。【允许空表】
有限性、序列。
-
直接前驱、直接后继
- 谁有:0-n-1——有直接后继
-
线性表的基本操作【考试直接用的那种】
- InitList (*L)
- ListEmpty (L)
- ClearList (*L)
- GetElem (L, i, *e)
- LocateElem(L, e)
- ListInsert (*L, i, e)
- ListDelete (*L, i, e)
- ListLength (L)
链式存储
-
定义
结点定义如下:
typedef struct LNode{ ElemType data; struct LNode *next; }LNode, *LinkList;
除了数据以外,还有一个存放其后继的指针。离散存储,【失去了随机存取】
-
基本操作
-
建立单链表
-
头插法:【插入时间为 O ( 1 ) O(1) O(1),但是,与原始插入顺序相反】
【带有头节点版】
LinkList List_head_Insert(LinkList &L) { LNode *s; int x; L = (LinkList) malloc(sizeof(LNode)); L -> next = NULL; scanf("%d",&x); while(x!=-1) { s = (LNode *)malloc (sizeof(LNode)); s -> data = x; s -> next = L -> next; L -> next = s; scanf("%d",&x); } return L; }
【不带有头节点版】
LinkList List_head_Insert(LinkList &L_head) { LNode *s; int x; L_head = (LinkList) malloc(sizeof(LNode)); L_head -> next = NULL; scanf("%d",&x); if (x == -1) // end of the link { delete(L_head); return NULL; } L_head -> data = x; scanf("%d",&x); while(x!= -1) { s = (LNode *)malloc (sizeof(LNode)); s -> data = x; s -> next = L_head; L_head = s; scanf("%d",&x); } return L_head; }
-
尾插法
【带有头节点版】
LinkList List_head_Insert(LinkList &L) { LNode *s, *rear; int x; L = (LinkList) malloc(sizeof(LNode)); // 建立头节点 L -> next = NULL; rear = L; scanf("%d",&x); while(x!=-1) { s = (LNode *)malloc (sizeof(LNode)); s -> data = x; s -> next = NULL; rear -> next = s; rear = s; scanf("%d",&x); } return L; }
【不带有头节点版】
LinkList List_head_Insert(LinkList &L_head) { LNode *s, *rear; int x; L_head = (LinkList) malloc(sizeof(LNode)); L_head -> next = NULL; scanf("%d",&x); if (x == -1) // end of the link { delete(L_head); return NULL; } L_head -> data = x; rear = L_head; scanf("%d",&x); while(x!= -1) { s = (LNode *)malloc (sizeof(LNode)); s -> data = x; s -> next = NULL; rear -> next = s; rear = s; scanf("%d",&x); } return L_head; }
-
-
查找
- 按值查找 :just a for-loop【 O ( N ) O(N) O(N)】
- 按序号查找:失去了随机存取的特性【 O ( N ) O(N) O(N)】
-
插入
-
后插
int List_head_Insert (LinkList &L_head, LNode *insert_point, LNode *location)// L_head是单链表,insert_point为要插入的结点,而location是插入的位置的指针 { // 为什么没必要呢?因为已经给定了location结点了。可以直接用它来了做后插了。 ~~LNode *p = L_head -> next; LNode *mid; while(p -> next) { if (p == location) {~~ mid = p -> next; p -> next = insert_point; insert_point -> next = mid; return 1; // 可以不要mid insert_point -> next = p -> next; p -> next = insertion; ~~} p = p -> next; } return 0; }~~
-
前插
【一种比较笨的前插】: O ( N ) O(N) O(N)
int List_head_Insert (LinkList &L_head, LNode *insert_point, LNode *location)// L_head是单链表,insert_point为要插入的结点,而location是插入的位置的指针 { LNode *p = L_head -> next; LNode *fore_point = L_head ; LNode *mid; while(p -> next) { if (p == location) { mid = fore_point -> next; fore_point -> next = insert_point; insert_point -> next = mid; return 1; } fore_point = p; p = p -> next; } return 0; }
【一种基于交换结点data的后插】: O ( 1 ) O(1) O(1)
int List_head_Insert (LinkList &L_head, LNode *insert_point, LNode *location)// L_head是单链表,insert_point为要插入的结点,而location是插入的位置的指针 { LNode *mid = location -> next; location -> next = insert_point; insert_point -> next = mid; // 可以不要mid insert_point -> next = p -> next; p -> next = insertion; swap(location -> data, insert_point -> data); return 1; }
-
-
删除
O ( N ) O(N) O(N)
-
几种改进链表
408考试中还没有出现以下几种列表。请酌情复习。
双链表
前驱+后继
typedef struct DNode
{
ElemType data;
struct DNode *prior, *next;
}DNode, *DLinkList;
循环链表
最后一个结点的指针指向头结点。
静态链表
利用数组的存放,进行模拟。
补充:一元多项式的计算和存储
单链表算法题常用套路
原地逆置算法
【利用头插法的思想】
空间复杂度为 O ( 1 ) O(1) O(1),时间复杂度为 O ( N ) O(N) O(N)
void reverse_in_O_1(LNode &L)
{
LNode *p, *fast;
p = L.next;
while (p != NULL)
{
fast = p -> next;
p -> next = L.next;
L.next = p;
p = tmp;
}
}
单链表双指针处理
【用一次遍历,找到链表中间结点n/2的那个点。】
空间复杂度 O ( 1 ) O(1) O(1),时间复杂度 O ( N ) O(N) O(N)
int find_mid(LinkList &L)
{
LNode *p, *p2;
p = L.next;
p2 = L.next;
while(p2 == NULL || p2->next == NULL)
{
p2 = p2 -> next -> next;
p = p -> next;
}
return p -> data;
}
【用一次遍历,找到链表的倒数第k个元素】
空间复杂度 O ( 1 ) O(1) O(1),时间复杂度 O ( N ) O(N) O(N)
int find_k(LinkList &L, int k)
{
LNode *p = L.next, *pk = L.next;
while (k--)
{
pk = pk -> next;
}
if (pk == NULL)
return -1; //链表长度小于k
while(pk)
{
pk = pk -> next;
p = p -> next;
}
return p -> data;
}