将单链表按基准划分(C语言实现)
目的:掌握单链表的应用和算法设计
内容:以给定值x为基准将单链表分割为两部分,所有小于x的结点排在大于或等于x的结点之前。
思路:创建一个新的头结点,将小于基准的结点接到新的头结点之后并将其从原本的链表中删除,然后再将新的链表接到原本的链表之前。
算法实现:
bool DivideList(LinkNode*& L, ElemType x) //L为传入的链表头结点,x为传入的基准
{
if (L->next==NULL) {
printf("单链表不存在。\n");
return false;
}
LinkNode* p = NULL, * q = NULL, * r = NULL; //p为工作指针,q为小于基准的数的头结点,r为尾指针
p = L;
//直到申请成功,因为malloc可能申请失败
while (!q) {
q = (LinkNode*)malloc(sizeof(LinkNode));
}
r = q; //r指向小于基准的链表的尾巴
//p从第一个有效结点开始扫描整个链表,直到p后无结点为空
while (p->next) {
if (p->next->data < x) {
r->next = p->next; //将p接到尾巴后面
r=r->next; //尾巴后移
p->next= p->next->next; //将该结点从L中截取出去
r->next = NULL; //将尾巴与原链表之间的关系切断
}
else
p = p->next; //p后移
}
//将小于基准的链表接到大于等于基准的链表的前面
r->next = L->next; //小于基准的链表的尾巴与大于等于基准的链表相连
L->next = q->next; //将整体接到头结点后
free(q); //释放小于基准的链表的头结点
return true;
}
bool DivideList(LinkNode*& L, ElemType x)中用到了引用参数,引用参数在C++里才有,所以源代码文件格式应为".cpp"。
与主函数相结合
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode* next;
}LinkNode;
bool DivideList(LinkNode*& L, ElemType x); //L为传入的链表头结点,x为传入的基准
bool InitList(LinkNode*& L); //链表产生
bool DispList(LinkNode* L); //链表输出
int main(int argc, const char* argv[])
{
LinkNode* L = NULL;
int x;
bool flag = false;
InitList(L);
printf("请输入基准。\n");
scanf("%d", &x);
flag = DivideList(L, x);
if (flag)
printf("算法执行成功。\n");
else
printf("算法执行失败。\n");
DispList(L);
return 0;
}
bool InitList(LinkNode*& L) //建立单链表
{
while (!L) {
L = (LinkNode*)malloc(sizeof(LNode));
}
L->next = NULL;
int i, n;
LinkNode* p = NULL, * q = NULL;
q = L;
printf("请输入数据规模:\n");
scanf("%d", &n);
printf("请输入数据:\n");
for (i = 0; i < n; i++) {
while (!p) {
p = (LinkNode*)malloc(sizeof(LNode));
}
scanf("%d", &p->data);
q->next = p;
q = p;
p = q->next = NULL;
}
return true;
}
bool DispList(LinkNode* L) //输出单链表
{
LinkNode* p = L->next;
while (p) {
printf("\t%d", p->data);
p = p->next;
}
printf("\n");
return true;
}
bool DivideList(LinkNode*& L, ElemType x) //L为传入的链表头结点,x为传入的基准
{
if (L->next==NULL) {
printf("单链表不存在。\n");
return false;
}
LinkNode* p = NULL, * q = NULL, * r = NULL; //p为工作指针,q为小于基准的数的头结点,r为尾指针
p = L;
//直到申请成功,因为malloc可能申请失败
while (!q) {
q = (LinkNode*)malloc(sizeof(LinkNode));
}
r = q; //r指向小于基准的链表的尾巴
//p从第一个有效结点开始扫描整个链表,直到p后无结点为空
while (p->next) {
if (p->next->data < x) {
r->next = p->next; //将p接到尾巴后面
r=r->next; //尾巴后移
p->next= p->next->next; //将该结点从L中截取出去
r->next = NULL; //将尾巴与原链表之间的关系切断
}
else
p = p->next; //p后移
}
//将小于基准的链表接到大于等于基准的链表的前面
r->next = L->next; //小于基准的链表的尾巴与大于等于基准的链表相连
L->next = q->next; //将整体接到头结点后
free(q); //释放小于基准的链表的头结点
return true;
}