Maison > interface Web > js tutoriel > le corps du texte

JavaScript implémente le tri par insertion de liste chaînée et le tri par fusion de liste chaînée

高洛峰
Libérer: 2016-12-29 15:50:17
original
1286 Les gens l'ont consulté

Cet article présente en détail l'implémentation JavaScript du tri par insertion de liste chaînée et du tri par fusion de liste chaînée consiste à fusionner et trier chaque partie, puis à les fusionner ensemble.

1. Liste chaînée

1.1 Représentation de stockage de la liste chaînée

//链表的存储表示
typedef int ElemType;
typedef struct LNode
{
  ElemType data;
  struct LNode *next;
}LNode, *LinkList;
Copier après la connexion

1.2 Opérations de base

Créer liste chaînée :

/*
 * 创建链表。
 * 形参num为链表的长度,函数返回链表的头指针。
 */
LinkList CreatLink(int num)
{
  int i, data;
  
  //p指向当前链表中最后一个结点,q指向准备插入的结点。
  LinkList head = NULL, p = NULL, q;
  
  for (i = 0; i < num; i++)
  {
    scanf("%d", &data);
    q = (LinkList)malloc(sizeof(LNode));
    q->data = data;
    q->next = NULL;
    if (i == 0)
    {
      head = q;
    }
    else
    {
      p->next = q;
    }
    p = q;
  }
  return head;
}
Copier après la connexion

Liste chaînée de sortie :

/*
 * 输出链表结点值。
 */
int PrintLink(LinkList head)
{
  LinkList p;
  for (p = head; p ;p = p->next)
  {
    printf("%-3d ", p->data);
  }
  return 0;
}
Copier après la connexion

2. Tri par insertion de liste chaînée

Idée de base : Supposons que le premier n-1. les nœuds sont dans l'ordre, et le n-ième nœud est inséré dans la position appropriée du nœud précédent pour mettre ces n nœuds dans l'ordre.

Méthode de mise en œuvre :

Démolissez le premier nœud de la liste chaînée pour devenir une liste chaînée contenant un nœud (head1), et les nœuds restants deviendront naturellement un autre Une liste chaînée (head2), à ce moment head1 est une liste chaînée ordonnée contenant un nœud


supprimez le premier nœud de la liste chaînée head2 et insérez-le dans le chaîné list head1 position appropriée pour que head1 soit toujours en ordre. À ce moment, head1 devient une liste chaînée ordonnée contenant deux nœuds

supprime à son tour un nœud de la liste chaînée head2 et l'insère dans le ; liste chaînée head1 jusqu'à ce que la liste chaînée head2 soit une liste chaînée vide. Enfin, la liste chaînée head1 contient tous les nœuds, et les nœuds sont dans l'ordre.

Code de tri par insertion :

/*
 * 链表插入排序(由小到大)。
 * 输入:链表的头指针,
 * 输出:排序后链表的头指针。
 * 实现方法:将原链表拆成两部分:链表1仍以head为头指针,链表结点有序。链表2以head2为头指针,链表结点无序。
 * 将链表2中的结点依次插入到链表1中,并保持链表1有序。
 * 最后链表1中包含所有结点,且有序。
 */
LinkList LinkInsertSort(LinkList head)
{
  //current指向当前待插入的结点。
  LinkList head2, current, p, q;
  
  if (head == NULL)
    return head;
  
  //第一次拆分。
  head2 = head->next;
  head->next = NULL;
  
  while (head2)
  {
    current = head2;
    head2 = head2->next;
  
    //寻找插入位置,插入位置为结点p和q中间。
    for (p = NULL, q = head; q && q->data <= current->data; p = q, q = q->next);
  
    if (q == head)
    {
      //将current插入最前面。
      head = current;
    }
    else
    {
      p->next = current;
    }
    current->next = q;
  }
  return head;
}
Copier après la connexion

Code source complet :

/*
 * 链表插入排序,由小到大
 */
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
 
#define TOTAL 10    //链表长度
 
//链表的存储表示
typedef int ElemType;
typedef struct LNode
{
  ElemType data;
  struct LNode *next;
}LNode, *LinkList;
 
LinkList CreatLink(int num);
LinkList LinkInsertSort(LinkList head);
int PrintLink(LinkList head);
 
/*
 * 创建链表。
 * 形参num为链表的长度,函数返回链表的头指针。
 */
LinkList CreatLink(int num)
{
  int i, data;
 
  //p指向当前链表中最后一个结点,q指向准备插入的结点。
  LinkList head = NULL, p = NULL, q;
 
  for (i = 0; i < num; i++)
  {
    scanf("%d", &data);
    q = (LinkList)malloc(sizeof(LNode));
    q->data = data;
    q->next = NULL;
    if (i == 0)
    {
      head = q;
    }
    else
    {
      p->next = q;
    }
    p = q;
  }
  return head;
}
 
/*
 * 链表插入排序(由小到大)。
 * 输入:链表的头指针,
 * 输出:排序后链表的头指针。
 * 实现方法:将原链表拆成两部分:链表1仍以head为头指针,链表结点有序。链表2以head2为头指针,链表结点无序。
 * 将链表2中的结点依次插入到链表1中,并保持链表1有序。
 * 最后链表1中包含所有结点,且有序。
 */
LinkList LinkInsertSort(LinkList head)
{
  //current指向当前待插入的结点。
  LinkList head2, current, p, q;
 
  if (head == NULL)
    return head;
 
  //第一次拆分。
  head2 = head->next;
  head->next = NULL;
 
  while (head2)
  {
    current = head2;
    head2 = head2->next;
 
    //寻找插入位置,插入位置为结点p和q中间。
    for (p = NULL, q = head; q && q->data <= current->data; p = q, q = q->next);
 
    if (q == head)
    {
      //将current插入最前面。
      head = current;
    }
    else
    {
      p->next = current;
    }
    current->next = q;
  }
  return head;
}
 
/*
 * 输出链表结点值。
 */
int PrintLink(LinkList head)
{
  LinkList p;
  for (p = head; p ;p = p->next)
  {
    printf("%-3d ", p->data);
  }
  return 0;
}
 
int main()
{
  LinkList head;
 
  printf("输入Total个数以创建链表:\n");
  head = CreatLink(TOTAL);
   
  head = LinkInsertSort(head);
  printf("排序后:\n");
  PrintLink(head);
  putchar('\n');
  return 0;
}
Copier après la connexion

Tri par fusion de liste chaînée

Idée de base : si la liste chaînée est vide ou contient un nœud, la liste chaînée est naturellement ordonnée. Sinon, divisez la liste chaînée en deux parties, triez par fusion chaque partie séparément, puis fusionnez les deux listes chaînées triées ensemble.

Code de tri de fusion :

/*
 * 链表归并排序(由小到大)。
 * 输入:链表的头指针,
 * 输出:排序后链表的头指针。
 * 递归实现方法:将链表head分为两部分,分别进行归并排序,再将排序后的两部分归并在一起。
 * 递归结束条件:进行递归排序的链表为空或者只有一个结点。
 */
LinkList LinkMergeSort(LinkList head)
{
  LinkList head1, head2;
  if (head == NULL || head->next == NULL)
    return head;
  
  LinkSplit(head, &head1, &head2);
  head1 = LinkMergeSort(head1);
  head2 = LinkMergeSort(head2);
  head = LinkMerge(head1, head2);
  return head;
}
Copier après la connexion

La fonction de fractionnement de liste chaînée est la suivante. L'idée de base est d'utiliser des pointeurs lents/rapides. Voir les commentaires pour la méthode d'implémentation spécifique. .

/*
 * 链表分割函数。
 * 将链表head均分为两部分head1和head2,若链表长度为奇数,多出的结点从属于第一部分。
 * 实现方法:首先使指针slow/fast指向链首,
 * 然后使fast指针向前移动两个结点的同时,slow指针向前移动一个结点,
 * 循环移动,直至fast指针指向链尾。结束时,slow指向链表head1的链尾。
 */
int LinkSplit(LinkList head, LinkList *head1, LinkList *head2)
{
  LinkList slow, fast;
  
  if (head == NULL || head->next == NULL)
  {
    *head1 = head;
    *head2 = NULL;
    return 0;
  }
  slow = head;
  fast = head->next;
  while (fast)
  {
    fast = fast->next;
    if (fast)
    {
      fast = fast->next;
      slow = slow->next;
    }
  }
  *head1 = head;
  *head2 = slow->next;
  
  //注意:一定要将链表head1的链尾置空。
  slow->next = NULL;
  return 0;
}
Copier après la connexion

La fonction de fusion de listes chaînées a deux méthodes : implémentation récursive et implémentation non récursive :

Implémentation non récursive :

/*
 * 链表归并。
 * 将两个有序的链表归并在一起,使总链表有序。
 * 输入:链表head1和链表head2
 * 输出:归并后的链表
 * 实现方法:将链表head2中的结点依次插入到链表head1中的适当位置,使head1仍为有序链表。
 */
LinkList LinkMerge(LinkList head1, LinkList head2)
{
  LinkList p, q, t;
  
  if (!head1)
    return head2;
  if (!head2)
    return head1;
  
  //循环变量的初始化,q指向链表head1中的当前结点,p为q的前驱。
  p = NULL;
  q = head1;
  while (head2)
  {
    //t为待插入结点。
    t = head2;
    head2 = head2->next;
    //寻找插入位置,插入位置为p和q之间。
    for (;q && q->data <= t->data; p = q, q = q->next);
    if (p == NULL)
      head1 = t;
    else
      p->next = t;
    t->next = q;
    //将结点t插入到p和q之间后,使p重新指向q的前驱。
    p = t;
  }
  return head1;
}
Copier après la connexion

Récursive mise en œuvre :

LinkList LinkMerge2(LinkList head1, LinkList head2)
{
  LinkList result;
  
  if (!head1)
    return head2;
  if (!head2)
    return head1;
  
  if (head1->data <= head2->data)
  {
    result = head1;
    result->next = LinkMerge(head1->next, head2);
  }
  else
  {
    result = head2;
    result->next = LinkMerge(head1, head2->next);
  }
  return result;
}
Copier après la connexion

Code source complet :

/*
* 链表归并排序,由小到大。
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
 
#define TOTAL 10    //链表长度
 
//链表的存储表示
typedef int ElemType;
typedef struct LNode
{
  ElemType data;
  struct LNode *next;
}LNode, *LinkList;
 
LinkList CreatLink(int num);
LinkList LinkMergeSort(LinkList head);
LinkList LinkMerge(LinkList head1, LinkList head2);
LinkList LinkMerge2(LinkList head1, LinkList head2);
int LinkSplit(LinkList head, LinkList *head1, LinkList *head2);
int PrintLink(LinkList head);
 
/*
* 创建链表。
* 形参num为链表的长度,函数返回链表的头指针。
*/
LinkList CreatLink(int num)
{
  int i, data;
 
  //p指向当前链表中最后一个结点,q指向准备插入的结点。
  LinkList head = NULL, p = NULL, q;
 
  for (i = 0; i < num; i++)
  {
    scanf("%d", &data);
    q = (LinkList)malloc(sizeof(LNode));
    q->data = data;
    q->next = NULL;
    if (i == 0)
    {
      head = q;
    }
    else
    {
      p->next = q;
    }
    p = q;
  }
  return head;
}
 
/*
* 输出链表结点值。
*/
int PrintLink(LinkList head)
{
  LinkList p;
  for (p = head; p; p = p->next)
  {
    printf("%-3d ", p->data);
  }
  return 0;
}
 
int main()
{
  LinkList head;
 
  printf("输入Total个数以创建链表:\n");
  head = CreatLink(TOTAL);
 
  head = LinkMergeSort(head);
  printf("排序后:\n");
  PrintLink(head);
  putchar(&#39;\n&#39;);
  return 0;
}
 
/*
 * 链表归并排序(由小到大)。
 * 输入:链表的头指针,
 * 输出:排序后链表的头指针。
 * 递归实现方法:将链表head分为两部分,分别进行归并排序,再将排序后的两部分归并在一起。
 * 递归结束条件:进行递归排序的链表为空或者只有一个结点。
 */
LinkList LinkMergeSort(LinkList head)
{
  LinkList head1, head2;
  if (head == NULL || head->next == NULL)
    return head;
 
  LinkSplit(head, &head1, &head2);
  head1 = LinkMergeSort(head1);
  head2 = LinkMergeSort(head2);
  head = LinkMerge(head1, head2);    //非递归实现
  //head = LinkMerge2(head1, head2);  //递归实现
  return head;
}
 
/*
 * 链表归并。
 * 将两个有序的链表归并在一起,使总链表有序。
 * 输入:链表head1和链表head2
 * 输出:归并后的链表
 * 实现方法:将链表head2中的结点依次插入到链表head1中的适当位置,使head1仍为有序链表。
 */
LinkList LinkMerge(LinkList head1, LinkList head2)
{
  LinkList p, q, t;
 
  if (!head1)
    return head2;
  if (!head2)
    return head1;
 
  //循环变量的初始化,q指向链表head1中的当前结点,p为q的前驱。
  p = NULL;
  q = head1;
  while (head2)
  {
    //t为待插入结点。
    t = head2;
    head2 = head2->next;
    //寻找插入位置,插入位置为p和q之间。
    for (;q && q->data <= t->data; p = q, q = q->next);
    if (p == NULL)
      head1 = t;
    else
      p->next = t;
    t->next = q;
    //将结点t插入到p和q之间后,使p重新指向q的前驱。
    p = t;
  }
  return head1;
}
 
LinkList LinkMerge2(LinkList head1, LinkList head2)
{
  LinkList result;
 
  if (!head1)
    return head2;
  if (!head2)
    return head1;
 
  if (head1->data <= head2->data)
  {
    result = head1;
    result->next = LinkMerge(head1->next, head2);
  }
  else
  {
    result = head2;
    result->next = LinkMerge(head1, head2->next);
  }
  return result;
}
 
/*
 * 链表分割函数。
 * 将链表head均分为两部分head1和head2,若链表长度为奇数,多出的结点从属于第一部分。
 * 实现方法:首先使指针slow/fast指向链首,
 * 然后使fast指针向前移动两个结点的同时,slow指针向前移动一个结点,
 * 循环移动,直至fast指针指向链尾。结束时,slow指向链表head1的链尾。
 */
int LinkSplit(LinkList head, LinkList *head1, LinkList *head2)
{
  LinkList slow, fast;
 
  if (head == NULL || head->next == NULL)
  {
    *head1 = head;
    *head2 = NULL;
    return 0;
  }
  slow = head;
  fast = head->next;
  while (fast)
  {
    fast = fast->next;
    if (fast)
    {
      fast = fast->next;
      slow = slow->next;
    }
  }
  *head1 = head;
  *head2 = slow->next;
 
  //注意:一定要将链表head1的链尾置空。
  slow->next = NULL;
  return 0;
}
Copier après la connexion

Ce qui précède est l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'apprentissage de chacun, et j'espère également que tout le monde. prendra en charge le site Web chinois PHP.

Pour plus d'implémentations JavaScript du tri par insertion de liste chaînée et du tri par fusion de liste chaînée, veuillez faire attention au site Web PHP chinois !


Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!