如何在C中的函数中按名称对链接列表进行排序?
struct rec{
char name[20];
int nr;
struct rec *nextRec;
};
typedef struct rec Rec; /* synonym for struct rec */
typedef Rec *RecPtr; /* synonym for pointer */
void SortLinkedList(RecPtr *sPtr, int p_size);/* prototype */
int main() {
RecPtr startPtr = NULL;
/* filling upp the linked list... size = nr of nodes in list */
SortLinkedList(&startPtr, size);
}
void SortLinkedList(RecPtr *sPtr, int p_size){
int i, j;
RecPtr tempPtr;
RecPtr currentPtr;
RecPtr nextPtr;
currentPtr = *sPtr;
nextPtr = currentPtr->nextRec;
for( j = 0; j <= p_size; j++) { /* loop for nr of nodes */
for(i = 0; i <= p_size -1 ; i++) { /* loop for one less than nr of nodes */
if(strcmp(currentPtr->name, nextPtr->name) < 0) { /* it less than ...*/
tempPtr = currentPtr;/* ...swap with temp */
currentPtr = nextPtr; /* but this sorting doesn'nt work */
nextPtr = tempPtr;
}
currentPtr = nextPtr;
currentPtr = currentPtr->nextRec;
}
}
}
答案 0 :(得分:2)
问题似乎是你只是操纵指针而不是对象本身。对链表进行排序时,必须断开链接并重新制作链接。
例如,在您的情况下,有三个链接,它们必须按括号中的指定进行修改。
prevPtr-&gt; nextRec(需要将其更改为指向nextPtr而不是currentPtr) currentPtr-&gt; nextRec(需要将其更改为指向nextPtr-&gt; nextRec而不是nextPtr) nextPtr-&gt; nextRec(需要将其更改为指向currentPtr)
您必须拥有prevPtr并在程序中跟踪它。
nextRec nextRec nextRec
prevPtr --------------&gt; currentPtr -------------------------&gt; nextPtr- --------------------------&GT; (nextPtr-&GT; NEXTREC)
需要改为
nextRec nextRec nextRec
prevPtr -----------------------&gt; nextPtr ------------------&gt; currentPtr -------------------&GT; (nextPtr-&GT; NEXTREC)
答案 1 :(得分:1)
您的问题是,当您应该操纵列表中结构的nextRec
字段时,您只是操纵RecPtr变量,这些变量没有永久效果。
答案 2 :(得分:1)
不是回答你的问题,而是回答几个问题:
答案 3 :(得分:1)
警告:以下内容很可能是您想要做的事情。但是,我很沮丧地试图找出一个微妙但令人讨厌的错误并需要分心。
如果我可以提供一些建议......
首先,IMO更容易按顺序将项目插入列表,而不是对无序列表进行排序;我要做的是创建一个insertInOrder函数,它接受你的列表头,要添加的新元素,以及一个比较记录的谓词(指向函数的指针),并返回列表的新头部:
Rec *insertInOrder(Rec *head, Rec *new, int (*cmp)(Rec *, Rec *))
{
if (head == NULL)
{
return new;
}
else if (cmp(new, head) < 0) // new is "less than" head
{
new->nextRec = head;
return new; // new becomes the new head of the list
}
else
{
Rec *tmp = head;
/**
* Find the first element in the list that is not "less than" new
*/
while (tmp->nextRec != NULL && cmp(new, tmp->nextRec) > 0)
{
tmp = tmp->nextRec;
}
if (tmp->nextRec == NULL)
{
// insert new at end of list
tmp->nextRec = new;
new->nextRec = NULL;
}
else
{
// insert new before tmp->nextRec
new->nextRec = tmp->nextRec;
tmp->nextRec = new;
}
// keep the current list head
return head;
}
}
现在您可以根据不同的标准订购列表。 cmp
参数指向一个函数,它接受两个记录指针并比较它们,如果第一个参数是“小于”第二个,则返回-1,如果第一个参数是“大于”第二个,则返回1,0如果他们比较平等。例如,如果要按名称排序,请定义类似
int compareNames(Rec *e1, Rec *e2)
{
int r = strcmp(e1->name, e2->name);
if (r < 0) return -1;
if (r > 0) return 1;
return 0;
}
并将insertInOrder调用为
head = insertInOrder(head, new, compareNames);
在给定特定谓词的情况下对列表进行排序:从头开始,从现有列表中一次删除一个元素,并使用指示的谓词将其添加到新列表中:
Rec *sortLinkedList(Rec *head, int (*cmp)(Rec *, Rec *))
{
Rec *newList = NULL;
while (head)
{
Rec *tmp = head;
head = head->nextRec;
tmp->nextRec = NULL;
newList = insertInOrder(newList, tmp, cmp);
}
return newList;
}
...
head = sortLinkedList(head, compareNr);
...
head = sortLinkdeList(head, compareNames);
...
head = sortLinkedList(head, compareSomethingElse);
像Neil一样,我并不十分喜欢指针类型的typedef;经验告诉我,他们造成的问题多于他们的价值。
答案 4 :(得分:0)
如果您要更改链接列表的顺序,那么在某个阶段您将不得不写入链接列表中的nextRec
指针。由于您所做的唯一分配是本地指针变量,因此您不会对列表进行任何更改。
你没有在i
循环和j
循环之间进行任何重置,因此很难看出你的算法如何保证不会超出列表的末尾,尽管它通常不会移动很远。
如果strcmp
测试没有触发两次迭代,那么它将始终单独nextPtr
并始终将currentPtr
分配给nextPtr->nextRec
,因此nextPtr
都不会并且currentPtr
也会改变。
currentPtr = nextPtr;
currentPtr = currentPtr->nextRec;
你真的是要在循环体中使用i++
以及for循环的增量部分吗?
您的排序算法是什么?请注意,如果您需要在单个链接列表中交换两个元素位置,则需要将先前的节点保留到要交换的元素,以便您可以调整先前节点的“下一个”指针。
答案 5 :(得分:0)
您可以轻松地对带有冒泡排序的链表进行排序(迭代它,在交换的情况下跟踪第i-1个元素)。你也可以很容易地做一个快速排序(事实上,我听说有些人认为quicksort在链表上比在数组上更有意义。)
答案 6 :(得分:0)
您可以通过选择排序或冒泡排序对列表进行排序。您需要交换指针而不是数据。下面我给出了两个可能对您的问题有帮助的例子。
struct link
{
int data;
struct link *next;
};
selection(struct link **first)
{
struct link *p,*q,*pp,*qq,*temp;
pp=p=*first;
while(p->next!=NULL)
{
q=p->next;
while(q!=NULL)
{
if(p->data > q->data)
{
if(p==*first)
{
if(q==p->next)
{
p->next=q->next;
q->next=p;
}
else
{
temp=q->next;
q->next=p->next;
p->next=temp;
qq->next=p;
}
*first=q;
pp=*first;
}
else
{
if(q==p->next)
{
p->next=q->next;
q->next=p;
pp->next=q;
}
else
{
temp=q->next;
q->next=p->next;
p->next=temp;
qq->next=p;
pp->next=q;
}
}
temp=p;
p=q;
q=temp;
}
qq=q;
q=q->next;
}
pp=p;
p=p->next;
}
return 0;
}
bable(struct link **first)
{
struct link *p,*q,*lt,*pp,*temp;
lt=NULL;
p=*first;
while((*first)->next!=lt)
{
pp=p=*first;
while(p->next!=lt)
{
q=p->next;
if((p->data)>(q->data))
{
if(p==*first)
{
p->next=q->next;
q->next=p;
*first=q;
pp=*first;
}
else
{
p->next=q->next;
q->next=p;
pp->next=q;
}
temp=p;
p=q;
q=temp;
}
pp=p;
p=p->next;
}
lt=p;
}
return 0;
}
答案 7 :(得分:0)
我建议在列表上进行merge-sort,因为它是O(N Log N),而bubble-sort或inserted-sort都是O(N ^ 2)。
Here's good example of a simple singly linked list merge sort