原题是要实现两个已排序的单链表合并后还是已排序,但我在网上查了很多都无法直接实现.对于初学者给个算法是没多大用的,下面给出完整代码.主要思路就是先接尾再排序.而一般书是直接开始分情况if...else if...else嵌套排序.比较复杂.
/*关键:两个有序单链表的合并:其实本程序可以实现任意两个单链表的合并排序,思想就是 *1.建两个链表2.合并两个链表3.对合并后的链表排序4.打印 *关键函数:linkDList 直接连接两个链表;selectsort 单链表的选择排序*/ #define _CRT_SECURE_NO_WARNINGS #include "stdio.h" #include "malloc.h" #include "windows.h"//system()所在 typedef char ElemType; typedef struct dNode {//声明单链表结点类型 ElemType data; //数据域,注意此单链表结点类型是字符型.有什么办法可以泛化呢? struct dNode *next; //指针域 }LNode, *LinkList; //定义此结构体变量struct dNode a或LNode a;定义此结构体的指针struct dNode *p或LNode *p或LinkList p都是没区别的 //此函数本程序没用到,只是为了和后面的CreateDListTail对应 LinkList CreateDListHead(LinkList head) { ElemType temp; LinkList p; printf("请输入结点值"); fflush(stdin); scanf("%c", &temp); while (temp!='0') { if (('A' <= temp&&temp <= 'Z') || ('a' <= temp&&temp <= 'z')) { p = (LinkList)malloc(sizeof(LNode)); p->data = temp; p->next = head->next; head->next = p; } printf("请输入结点值(输入0结束):"); fflush(stdin); scanf("%c", &temp); } return head; } LinkList CreateDListTail(LinkList Tail) //尾插法建立链表 { ElemType temp; LinkList s, r; printf("请输入结点值"); fflush(stdin); scanf("%c", &temp); r = Tail; while (temp!='0') { if (('A' <= temp&&temp <= 'Z') || ('a' <= temp&&temp <= 'z')) { s = (LinkList)malloc(sizeof(LNode)); s->data = temp; r->next = s; r = s; } printf("请输入结点值(输入0结束):"); fflush(stdin); scanf("%c", &temp); } r->next = NULL; return Tail; } void PrintDList(LinkList head) { LinkList p; int i = 0; p = head->next;//p指向第一个结点.这一步原head后的结点都会跑到p后 while (p != NULL) { i++; printf("第%d个元素是:", i); printf("%c\n", p->data); p = p->next; } printf("\n"); } void linkDList(LinkList S, LinkList T) {/*连接2个单链表*/ LinkList temp = S; while (temp->next != NULL) temp = temp->next; temp->next = T->next; PrintDList(S); } void selectsort(LinkList A) {//将降序排列 ElemType t; LinkList p, q, s;//q,s比较 if ((A->next) && (A->next->next)) //链表为空或只有一个结点时不用排序 { p = A->next; while (p->next) { q = p->next;w s = p; while (q) { if (q->data > s->data) { t = q->data; q->data = s->data; s->data = t; } q = q->next; }//endwhile 交换s结点和p结点的数据 p = p->next; }//endwhile }//endif PrintDList(A); }//endselectsort void main() { LinkList A=(LinkList)malloc(sizeof(LNode)); LinkList B = (LinkList)malloc(sizeof(LNode)); CreateDListTail(A); PrintDList(A); CreateDListTail(B); PrintDList(B); linkDList(A, B); selectsort(A); system("PAUSE"); free(A); free(B); }
代码通过VS 2013 + win 7 64 ;编译通过可运行,静态分析未通过,主要提示内存安全,API没返回值.
这个程序仅仅实现题目功能,一点都不完美.初学者能运行过谢天谢地了.
此外,代码的main部分应该可以简化吧,但是我不会.请前辈们指教.
补充需求:如果输入了自己原本不想输入的数据,应该再加点增加体验.
-----------------------------------------------------------------------------------------------------------------------------------
文章更新 150527
selectsort
问题目标:排序单链表
排除分析:链表只有0到1个结点不用排序 if ((A->next) && (A->next->next)) 为什么这么写? A有头结点,头结点不算单链表的内容.
至于&& 这个操作符要求两边的表达式都是true整条表达式才是true 就是说满足不是空表且不只含一个结点才进行if体内的语句.可以看出我程序没有写这个if剩下的else,不知道在业界规范不.
思路:循环比较
1.任选一个结点作为基准 这里是p p = A->next; 也就是链表A的第一个结点,p指向A的第一个,这个p以后会变成第二个第三个....
注意这个从前往后的过程 什么时候结束呢? while (p->next) 也就是p如果指向了最后一个结点就结束. 单链表的尾结点指针是NULL,这个NULL指向的数据域未知.
2.很明显有个内外遍历
外循环负责比较基准的后移,内循环负责比较的后移
难点:P到底什么用?
注意第15,此处是不能写s=s->next的,因为很可能s的值被换了,本来s是外部控制外部循环的,所以用p来跟踪外部循环的走向.
1 while (p->next) //while外循环:遍历 2 { 3 q = p->next; 4 s = p; //前两句保存两个指针,初始值一个是第一个,一个是第二个.q是内循环变量,所以下面的while要判断q是否为NULL,为NULL就说明这一轮比较完了,应该让s+1 () 5
while (q) //内循环:逐此比较 (4) 6 { 7 if (q->data > s->data) //if语句比较q和s数据域的大小 里面是常用的交换代码(要用到中间变量) (6) 8 { 9 t = q->data; 10 q->data = s->data; 11 s->data = t; 12 } 13 q = q->next; //比较完了 q就后移一位,然后又回到if语句跟第一个进行比较:q是内循环变量 (5) 14 }//endwhile 15
p = p->next; //这么往后总会变NULL (2) 16 }//endwhile (1)
序号代码正常的思维过程和码代码过程.