方法一:不进行任何断链插入操作,找到目标节点之后,只是交换data值,这个思路很简单,与简单选择排序的思路一摸一样。
编程注意事项:
min不能标记最小值,应该要标记最小值对应的链表节点
LinkList createLink(LinkList L) {
cout << "尾插法创建单链表:"<<endl;
int a;
L = (LinkList)malloc(sizeof(LinkNode));
L->next = NULL;
LinkNode *p=L,*r = L;
while (true)
{
cin >> a;
p = (LinkList)malloc(sizeof(LinkNode));
p->data = a;
r->next = p;
r = p;
if (cin.get() == '\n')break;
}
r->next = NULL;
return L;
}
void printList(LinkList L) {
LinkNode *p = L->next;
while (p)
{
cout << p->data << " ";
p = p->next;
}
}
LinkList sortList(LinkList L) {
LinkNode* p = L->next;
LinkNode* q;
LinkNode* min;
int temp;
while (p)
{
min = p;//有序序列中的最后位置元素节点
q = p->next;
while (q)
{
if (min->data > q->data)min=q;
q = q->next;//寻找无序序列中的最小值节点
}
if (min!= p) {//交换data值
temp = min->data;
min->data = p->data;
p->data = temp;
}
p = p->next;
}
return L;
}
int main() {
//基于单链表的简单选择排序
LinkList L=NULL;
L=createLink(L);
L = sortList(L);
cout << endl;
printList(L);
}
但是,再一次审题:在基于单链表表示的待排序关键字序列上进行简单选择排序,题目想要我们有断链插入操作,而不是直接修改data值,因此,还需要思考另一种方法。
方法二:
思路:每一趟找到未排序序列中的最大值,然后把最大值用头插法插入入新的单链表的首部,既然有插入和删除节点的操作,所以必然需要有指针来标记前驱节点,我们引入两个前驱:pre代表遍历的时候的前驱,pre_max代表目标最大值的前驱。
编程注意事项:
1.在存储了单链表的第一个节点之后,马上把头结点断开,为新的单链表做准备,很多关于单链表的题目都有这个步骤:断开头结点!!否则指针绝对会出错。
2.只有在未排序序列的首部节点已经是最大值节点的时候才需要移动外循环的标记指针,具体可以看下图的实现过程。
LinkList sortList02(LinkList L) {
//每次找到最大的插入到链表的最前端
LinkNode* h = L->next;
LinkNode* max, *p, *pre, *pre_max;
L->next = NULL;
while (h)
{
max=p= h;
pre =pre_max = NULL;
while (p)
{
if (p->data > max->data) {
pre_max = pre;
max = p;
}
pre = p;
p = p->next;
}
//将max插入到头结点之后,并保持单链表链接
if (max == h) h = h->next;
else
pre_max->next = max->next;
max->next = L->next;
L->next = max;
}
return L;
}