【问题标题】:How would I modify this singly linked list sorting algorithm so that it sorts by ascending order properly?我将如何修改这个单链表排序算法,使其按升序正确排序?
【发布时间】:2020-04-04 01:07:07
【问题描述】:

我目前正在尝试按降序对单链表进行排序。意识到只有一个 next 指针没有直接的方法来做到这一点,我选择了先按升序对列表进行排序,然后将列表反转,以便项目按降序排序的方法。

编辑 1: 我试图确保项目根据它们在链接列表中的访问频率以降序存储。打印只是为了帮助我检查链表的顺序。

编辑 2: 要求的最低工作示例:

main.c

#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct node_struct {
    char *name;
    int accessCount;
    struct node_struct *next;
}Knowledge_Node;

int knowledge_put();
int knowledge_get();
void printList();
void sortList();
void reverseList();

Knowledge_Node *head = NULL;

int main(int argc, char*argv[]){
  // Putting James into the linked list
  knowledge_put("James");

  //Get the James node twice
  knowledge_get("James");
  knowledge_get("James");

  //Add Carrie to the linked list
  knowledge_put("Carrie");

  //Get the Carrie node thrice
  knowledge_get("Carrie");
  knowledge_get("Carrie");
  knowledge_get("Carrie");

  // Add adams to linked list
  knowledge_put("Adams");
  knowledge_get("Adams");

  printList();
}

添加节点功能

int knowledge_put(char * name) {
  Knowledge_Node *node = (Knowledge_Node *)malloc(sizeof(Knowledge_Node));
  if (node == NULL) {
      return -3;
  }
  node->name = (char *)malloc(sizeof(char) * 255);
  if (node->name == NULL){
      return -3;
  }
  strncpy(node->name, name, strlen(name) + 1);
  node->accessCount = 0;

  node->next = head;
  head = node;

  sortList();
}

检索节点函数

int knowledge_get(char * name){
    Knowledge_Node *search = head;

    while (search != NULL){
        if (strcmp(search->name, name) == 0){
            search->accessCount = search->accessCount + 1;
            sortList();
            return 0;
        }
        search = search->next;
    }
    return -1;
}

排序列表功能:

void sortList(){
    Knowledge_Node *temp = head;
    Knowledge_Node *backPtr = head;
    Knowledge_Node *prevNode = NULL;

    while (temp != NULL){
        Knowledge_Node *nextNode = temp->next;
        //currentNode is assigned to temp, which is the pointer used to iterate through the list
        Knowledge_Node *currentNode = temp;
        //Doing a simple check to see if nextNode has something
        if (nextNode != NULL) {

            if(nextNode != NULL){
                if (currentNode->accessCount > nextNode->accessCount) {
                    //If previousNode is NULL it means currentNode is the head of //the linked list
                    //There's different logic to handle each case
                    if (prevNode != NULL){
                        prevNode->next = nextNode;
                        nextNode->next = currentNode;
                        currentNode->next = NULL;
                    } else if (prevNode == NULL){
                        currentNode->next = nextNode->next;
                        nextNode->next = currentNode;
                        head = nextNode;
                    }
                }
            }
        }
        //Assigning of previousNode. We'll need this for the linking/un-linking //process
        prevNode = currentNode;
        temp = temp->next;
    }
    reverseList();
} 

反向列表功能:

void reverseList(){
    //Initialise three pointers, which we'll use to reverse the links of the 
    //linked list
    Knowledge_Node *prevNode = NULL;
    Knowledge_Node *currentNode = head;
    Knowledge_Node *nextNode = NULL;

    //This is where the linked list reversal is done
    while (currentNode != NULL){
        nextNode = currentNode->next;
        currentNode->next = prevNode;
        prevNode = currentNode;
        currentNode = nextNode;
    }

    //Previous Node points to the last node in the original list, so let's 
    //make it the new head
    head = prevNode;
}

打印列表功能:

void printList() {
    Knowledge_Node *temp = head;
    while (temp != NULL){
        printf("%s %d\n", temp->name, temp->accessCount);
        temp = temp->next;
    }
}

预期输出:

Carrie 3
James 2
Adams 1

实际输出:

Adams 1
Carrie 3
James 2

没有反向排序,升序排序似乎可以正常工作。

希望有人可以基于此指导我如何更改 sortList 算法以使其按升序排序,然后正确降序排序

删除了其余内容以保持简短

【问题讨论】:

  • 你的“反向打印”函数可以递归吗?如果是这样,您可以对 升序 进行排序并仅以相反的顺序打印列表 [无需 创建 反向列表]。也许您应该发布您的反向/打印功能。发布您的整个代码可能会有所帮助。它应该干净地编译并且可以下载。另外,发布您的示例数据 [在代码块中]
  • @CraigEstey 我添加了一个最小工作示例来演示我想要做什么,也许你可以帮忙看看?
  • @luckyteos 您的代码需要更正什么?
  • @NemindaPrabhashwara 反向排序无法正常工作,这可能是由于升序排序不正确造成的。例如,3,2,1 应该排序为 1,2,3,但目前我得到的是 2,3,1。寻找一些帮助来改变算法的行为,使其正确排序
  • @luckyteos 错误出在您的排序算法中,而不是在反向函数中。

标签: c sorting


【解决方案1】:

我发现你的排序算法出了什么问题。由于您的链表是单链表,因此您不能使用更有效的排序算法,如插入排序。所以我在这件事上使用了冒泡排序。在您的算法中,您只使用了一个循环。您必须使用嵌套的两个循环。查看bubble sort的详细信息。

另外,您可以定义一个名为List 的结构并在其中包含头指针,而不是将列表的头指针保留为新添加的节点。更清楚了。

#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct node_struct {
    char *name;
    int accessCount;
    struct node_struct *next;

}Knowledge_Node;


typedef struct list{

    Knowledge_Node* head;
    int count;

}List;

int knowledge_put();
int knowledge_get();
void printList();
void sortList();
void reverseList();

List* list1=NULL;

int main(int argc, char*argv[]){

   list1= (List*)malloc(sizeof(List)*1);
   list1->head=NULL;
   list1->count=0;
  // Putting James into the linked list
  knowledge_put("James");

  //Get the James node twice
  knowledge_get("James");
  knowledge_get("James");

  //Add Carrie to the linked list
  knowledge_put("Carrie");

  //Get the Carrie node thrice
  knowledge_get("Carrie");
  knowledge_get("Carrie");
  knowledge_get("Carrie");

  // Add adams to linked list
  knowledge_put("Adams");
  knowledge_get("Adams");

  sortList();
  reverseList();
  printList();
}

int knowledge_put(char * name) {
  Knowledge_Node *node = (Knowledge_Node *)malloc(sizeof(Knowledge_Node));
  if (node == NULL) {
      return -3;
  }
  node->name = (char *)malloc(sizeof(char) * 255);
  if (node->name == NULL){
      return -3;
  }
  strncpy(node->name, name, strlen(name) + 1);
  node->accessCount = 0;


  node->next = list1->head;
  list1->head = node;
  list1->count++;


  return -3;
}

int knowledge_get(char * name){
    Knowledge_Node *search = list1->head;

    while (search != NULL){
        if (strcmp(search->name, name) == 0){
            search->accessCount = search->accessCount + 1;

            return 0;
        }
        search = search->next;
    }
    return -1;
}

void sortList(){

    Knowledge_Node* sort=list1->head;
    Knowledge_Node* nextl=list1->head->next;
    Knowledge_Node* temp=(Knowledge_Node *)malloc(sizeof(Knowledge_Node));
    temp->name = (char *)malloc(sizeof(char) * 255);
    //const Knowledge_Node* c_sort=list1->head;

    for(int i=0;i<list1->count-1;i++){

        while(nextl!=NULL&&sort!=NULL){

            if(sort->accessCount > nextl->accessCount){

                temp->accessCount=sort->accessCount;
                strncpy(temp->name,sort->name,strlen(sort->name)+1);
                sort->accessCount=nextl->accessCount;
                strncpy(sort->name,nextl->name,strlen(nextl->name)+1);
                nextl->accessCount=temp->accessCount;
                strncpy(nextl->name,temp->name,strlen(temp->name)+1);

            }
            sort=sort->next;
            nextl=nextl->next;

        }
        sort=list1->head;
        nextl=list1->head->next;

    }


}

void reverseList(){
    //Initialise three pointers, which we'll use to reverse the links of the
    //linked list
    Knowledge_Node *prevNode = NULL;
    Knowledge_Node *currentNode = list1->head;
    Knowledge_Node *nextNode = NULL;

    //This is where the linked list reversal is done
    while (currentNode != NULL){
        nextNode = currentNode->next;
        currentNode->next = prevNode;
        prevNode = currentNode;
        currentNode = nextNode;
    }

    //Previous Node points to the last node in the original list, so let's
    //make it the new head
    list1->head = prevNode;
}

void printList() {
    Knowledge_Node *temp = list1->head;
    while (temp != NULL){
        printf("%s %d\n", temp->name, temp->accessCount);
        temp = temp->next;
    }
}

【讨论】:

  • 啊,谢谢。我已经花了很长时间试图解决这个问题,尤其是当涉及到这么多指针时。虽然,我最初想做的是做你上面做的事情,但是通过重新链接节点,但总是遇到一个问题,即前一个节点是什么以及我应该如何将它与所有其他节点进行比较以检查它在正确的位置。谢谢你告诉我单链表是不可能的。
  • @luckyteos 是的,如果你想检查以前的节点,你必须有一个双向链表。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-15
  • 2021-07-22
  • 2018-03-08
  • 2014-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多