C中链表的插入排序?
Posted
技术标签:
【中文标题】C中链表的插入排序?【英文标题】:Insertion sort on linked list in C? 【发布时间】:2013-04-04 07:30:12 【问题描述】:我尝试搜索与我类似的问题,但没有找到太多帮助。
我有一个此类结构的链接列表:
struct PCB
struct PCB *next;
int reg1, reg2;
;
我首先创建了 10 个以这种方式链接在一起的 PCB 结构:
for(i=20;i<=30;i++)
curr = (struct PCB *)malloc(sizeof(struct PCB));
curr->reg1 = i;
curr->next = head;
head = curr;
然后我需要再创建 20 个 PCB 结构,但它们的 reg1
值需要使用 rand()
生成。我目前正在这样做:
for (j = 0;j<20;j++)
curr = (struct PCB *)malloc(sizeof(struct PCB));
curr->reg1 = rand()%100;
curr->next = head;
head = curr;
但是,当将这些 PCB 结构插入到带有随机 reg1
值的链表中时,我需要将它们按顺序插入到链表中(插入排序)。仅在单链接链表中解决此问题的最佳方法是什么?谢谢
编辑: 我现在正在跟踪第一个创建的结构,以便能够从头开始循环遍历链表:
// create root struct to keep track of beginning of linked list
root = (struct PCB *)malloc(sizeof(struct PCB));
root->next = 0;
root->reg1 = 20;
head = NULL;
// create first 10 structs with reg1 ranging from 20 to 30
for(i=21;i<=30;i++)
curr = (struct PCB *)malloc(sizeof(struct PCB));
// link root to current struct if not yet linked
if(root->next == 0)
root->next = curr;
curr->reg1 = i;
curr->next = head;
head = curr;
然后,当我创建另外 10 个需要插入排序的 PCB 结构时:
// create 20 more structs with random number as reg1 value
for (j = 0;j<20;j++)
curr = (struct PCB *)malloc(sizeof(struct PCB));
curr->reg1 = rand()%100;
// get root for looping through whole linked list
curr_two = root;
while(curr_two)
original_next = curr_two->next;
// check values against curr->reg1 to know where to insert
if(curr_two->next->reg1 >= curr->reg1)
// make curr's 'next' value curr_two's original 'next' value
curr->next = curr_two->next;
// change current item's 'next' value to curr
curr_two->next = curr;
else if(!curr_two->next)
curr->next = NULL;
curr_two->next = curr;
// move to next struct in linked list
curr_two = original_next;
head = curr;
但这立即使我的程序崩溃。
【问题讨论】:
【参考方案1】:“最佳”方法可能是为插入实现一个新功能。此函数将遍历列表,直到找到next
节点值小于或等于您要插入的节点的节点,然后将新节点放在next
节点之前。
这个功能怎么样:
void insert(struct PCB **head, const int reg1, const int reg2)
struct PCB *node = malloc(sizeof(struct PCB));
node->reg1 = reg1;
node->reg2 = reg2;
node->next = NULL;
if (*head == NULL)
/* Special case, list is empty */
*head = node;
else if (reg1 < (*head)->reg1)
/* Special case, new node is less than the current head */
node->next = *head;
*head = node;
else
struct PCB *current = *head;
/* Find the insertion point */
while (current->next != NULL && reg1 < current->next->reg1)
current = current->next;
/* Insert after `current` */
node->next = current->next;
current->next = node;
你可以这样称呼它:
insert(&root, rand() % 100, 0);
【讨论】:
但是我不需要双链接才能在我要插入的位置之前和之后获取节点吗? 不需要。在查看一个节点时,还要查看下一个节点。因此,对于每次迭代,您都持有两个引用:一个用于您正在查看的当前引用,另一个用于链接中的下一个引用。然后将这两个与您要插入的节点进行比较。 当 node->next == 0 或 node->next->key > key 时插入节点后 真的有人这样写代码吗?您不需要所有这些额外的情况......只需保留一个指向要插入的链接而不是节点的指针;最初是 &head,然后是 &node->next 在每次迭代之后。 对于那些想知道的人,是的,我的编程很冗长。当我认为其他人阅读和理解不会令人费解或更难时,我会进行概括。我相信编译器会做出比以往任何时候都更优化的代码,所以我更喜欢编写简单易读的小块,让编译器做它想做的任何转换。不,有时它不是最佳的,但至少我不需要花 15 分钟(或更多)来理解我的代码一年。【参考方案2】:这是@Joachim 的简化版:
void insert(struct PCB **head, const int reg1, const int reg2)
struct PCB *new ;
/* Find the insertion point */
for ( ;*head; head = & (*head)->next)
if ((*head)->reg1 > reg1) break;
new = malloc(sizeof *new );
new->reg1 = reg1;
new->reg2 = reg2;
new->next = *head;
*head = new;
这个想法很简单:不需要任何特殊情况,无论如何: 需要更改一个指针,这可能是根指针、尾指针或 LL 中间的某个指针。在任何/每种情况下:
新节点实际上窃取这个指针: 它使它指向它自己 它采用前一个值作为后继值(将其分配给它的->next
指针。
【讨论】:
但是嘿,我只复制了@Joachim 的评论!以上是关于C中链表的插入排序?的主要内容,如果未能解决你的问题,请参考以下文章