线性表之单链表
单链表的形式:
单链表的每节点中除了数据域外,还包含一个指针域,用来指向下一个节点,主要有带头结点和不带头结点两种。
单链表定义如下:
//单链表结构体定义 typedef struct LNode { int data; struct LNode* next; }LNode;
单链表中的两种基本算法:
插入操作:
.不妨设在节点A和节点B直间插入节点S,则具体分两步实现:
- 节点S指向节点B,
//让节点S指向B S->next = A->next;
- 节点A指向S
//节点A指S A->next = S
注意,这两步的顺序不能弄反,否则会丢失数据;
删除操作:
同理,不妨设删除节点B,则只需要找到前一个节点A即可,具体实现如下:
//p是要删除的节点 p = A->next; A->next = A->next->next; //释放节点B的空间 free(p);
具体的相关算法实现:
头插法建立单链表:
插入的新节点在表头,旧的节点在新节点之后,不妨设已有头节点B,现插入节点A,则形式为A->B,关键代码如下所示:
A->next = B->next;
B->next=A;
具体实现如下:
//插入的节点在表头 STATUS CreateListOfF(LNode *&P, int a[], int n) { //s用来指向新申请的节点 LNode* s; int i; //申请P的头结点 P =(LNode*) malloc(sizeof(LNode)); P->next = NULL; for (i = 0; i < n; i++) { s = (LNode*)malloc(sizeof(LNode)); s->data = a[i]; //新节点指向旧节点 s->next = P->next; //新节点称为新的开始节点 P->next = s; } return OK; }
尾插法建立单链表如下所示:
关键在于新插入的节点在链表的尾部,不妨设最后插入的节点是F,则最后必须加上F->next = NULL,具体实现如下:
//插入的节点在表尾 STATUS CreateListOfR(LNode *&P, int a[], int n) { //s指向新申请的节点,r直线链表的终端节点 LNode *s,*r; int i; //头结点的申请 P = (LNode*)malloc(sizeof(LNode)); P->next = NULL; r = P; for (i = 0; i < n; i++) { s = (LNode*)malloc(sizeof(LNode)); s->data = a[i]; //r指向终端节点 r->next = s; r = s; } r->next = NULL; return OK; }
打印链表元素:
STATUS PrintList(LNode *P) { if (P->next == NULL) { return ERROR; } while (P->next != NULL) { cout << P->next->data << "\t"; P = P->next; } cout << endl; return OK; }
查找某个元素并将其删除:
删除元素两个关键点:
- 待删除节点的查找;
- 待删除节点的前驱节点;
具体实现如下:
STATUS FindAndDel(LNode *&P,int x) { //pre指向待删除节点的前一个节点 LNode *pre, *p; p = P->next; pre = P; while (p != NULL) { if (p->data == x) { break; } pre = p; p = p->next; } //查找部分结束 if (p == NULL) { return ERROR; } else { //让p前驱节点指向p后继节点 pre->next = p->next; free(p); return OK; } }
将两个有序递增链表A、B合并成一个递增有序链表C:
递增有序链表在这使用尾插法,将两个有序的链表的元素一一比较,将较小的一个插入C中,依次递推。
注意: A和B中的元素有可能一个已经完全插入,另外一个部分插入。不妨设A完全插入,B部分插入,这说明B的剩下元素完全大于B,这是只需要将B接入C即可;
具体实现如下:
STATUS MergeListRise(LNode *A, LNode *B, LNode *&C) { LNode *pA = A->next; LNode *pB = B->next; C = A;
C->next = NULL; //r始终指向C节点 LNode *r; r = C; free(B); while (pA != NULL&&pB != NULL) { if (pA->data <= pB->data) { r->next = pA; r = pA;
pA = pA->next; } else { r->next = pB; r = pB;
pB = pB->next; } } r->next = NULL; //处理有一部分插完而另外一部分未插完; if (pA != NULL) { r->next = pA; } if (pB->next != NULL) { r->next = pB; } return OK; }
将两个有序递增链表A、B合并成一个递减有序链表C:
同上述合并成一个递增有序链表类似,但这里使用头插法构建C,不需要r指针指向C的尾节点,具体实现如下:
STATUS MergeListFall(LNode *A, LNode *B, LNode *&C) { LNode *pA = A->next; LNode *pB = B->next; C = A; C->next = NULL; free(B); //s指向待插入的节点 LNode *s; while (pA!=NULL&&pB!=NULL) { if (pA->data <= pB->data) { //取得待插入节点s s = pA; pA = pA->next; s->next = C->next; C->next = s; } else { s = pB; pB = pB->next; s->next = C->next; C->next = s; } } //当某一个链表先处理完时 while (pA != NULL) { s = pA; pA = pA->next; s->next = C->next; C->next = s; } while (pB != NULL) { s = pB; pB = pB->next; s->next = C->next; C->next = s; } return OK; }