区别于数组,数组的全部的元素在内存中都是连续存储的,而链表则是分散在内存中的,经过指针链接起来的一种数据结构。接下来,咱们尝试使用js合并两个有序链表。node
首先咱们须要声明一些咱们须要用到的函数。数组
每个节点一般最少有两个属性,一个表示该节点的值,能够用key来表示,另一个就是指向下一个节点的指针,能够用next表示。
先声明一个Node类:数据结构
function Node (key) { this.key = key; this.next = null; }
接着,声明一个链表类LinkedList:app
function LinkedList () { //表示链表的长度 this.length = 0; //表示链表的头结点(第一个节点) this.head = null; }
而后,再声明一个基本的链表方法append,用来向链表尾部插入一个新节点:函数
LinkedList.prototype.append = function (key){ var node = new Node(key); //若是链表尚未节点 if (!this.head) { this.head = node; } else { //经过循环找到最后一个节点,而后让最后一个节点指向新节点 var current = this.head; while(current.next){ current = current.next; } current.next = node; } // 修改链表的长度 this.length++; }
咱们的目的是合并有序链表,因此这里,咱们先用两个有序数组,去构建两个有序链表:测试
var arr1 = [2, 4, 6, 8]; var arr2 = [1, 3, 5, 7]; var list1 = new LinkedList(); var list2 = new LinkedList(); arr1.forEach(function(key){ list1.append(key); }); arr2.forEach(function(key){ list2.append(key); });
就是把两个链表中全部key都拿出来放进一个数组里,庵后,再对数组排序,根据数组,从新构建一个链表。this
function mergeLinkedList (list1, list2) { // 存放两个链表key的数组 var array = []; // 最终须要返回的新链表 var list = new LinkedList(); // 第一个链表的头节点 var listHead1 = list1.head; // 第二个链表的头节点 var listHead2 = list2.head; // 把第一个链表的全部key存进数组 while (listHead1) { array.push(listHead1.key); listHead1 = listHead1.next; } // 把第二个链表的全部key存进数组 while (listHead2) { array.push(listHead2.key); listHead2 = listHead2.next; } // 对数组排序 array = array.sort(function(a, b){ return a - b; }) // 使用数组从新构建一个链表 array.forEach(function(key){ list.append(key); }); return list; }
function mergeLinkedList (list1, list2) { var list = new LinkedList(); // 第一个链表的头节点 var current1 = list1.head; // 第二个链表的头节点 var current2 = list2.head; // 用循环把两个链表的key按顺序插入到新链表 while (current1 && current2) { if (current1.key < current2.key) { list.append(current1.key); current1 = current1.next; } else { list.append(current2.key); current2 = current2.next; } } // 找到新链表的最后一个节点 var current = list.head; while(current.next){ current = current.next; } // 循环完成之后,把第二个链表剩余部分插入到新链表 if (current2) { while (current2) { list.append(current2.key); current2 = current2.next; } } // 循环完成之后,把第一个链表剩余部分插入到新链表 if (current1) { while (current1) { list.append(current1.key); current1 = current1.next; } } return list; }
function mergeLinkedList (list1, list2) { var listHead1 = list1.head; var listHead2 = list2.head; var previous = listHead1; // 若是第二个链表的首节点key小于第一个链表的首节点key // 则构造一个新节点,并把新节点插入到第一个链表头部 if (listHead1.key > listHead2.key) { var node = new Node(listHead2.key); node.next = listHead1; list1.head = listHead1 = previous = node; listHead2 = listHead2.next; } // 循环比较两个链表的key,把第二个链表中的key插入到第一个链表合适的位置 while (listHead1 && listHead2) { if (listHead2.key < listHead1.key) { var node = new Node(listHead2.key); node.next = previous.next; previous.next = node; previous = node; listHead2 = listHead2.next; } else { previous = listHead1; listHead1 = listHead1.next; } } // 若是第二个链表比较长,则把剩余部分插入到第一个链表 while (listHead2) { var node = new Node(listHead2.key); if (listHead1) { listHead1.next = node; listHead1 = node; } else if (previous) { previous.next = node; previous = node; } listHead2 = listHead2.next; } // 修正第一个链表的长度 list1.length = list1.length + list2.length; return list1; }
仍是构造两个有序链表spa
var arr1 = [2, 4, 6, 8]; var arr2 = [1, 3, 5, 7]; var list1 = new LinkedList(); var list2 = new LinkedList(); arr1.forEach(function(key){ list1.append(key); }); arr2.forEach(function(key){ list2.append(key); }); var list = mergeLinkedList(list1, list2);
自控制台查看结果:prototype
换一组测试数据(arr1和arr2调换一下):指针
var arr2 = [2, 4, 6, 8]; var arr1 = [1, 3, 5, 7]; var list1 = new LinkedList(); var list2 = new LinkedList(); arr1.forEach(function(key){ list1.append(key); }); arr2.forEach(function(key){ list2.append(key); }); var list = mergeLinkedList(list1, list2);
看结果:
来一个复杂点的测试数据:
var arr1 = [99, 100, 104, 106]; var arr2 = [1, 3, 5, 7, 102, 103, 107]; var list1 = new LinkedList(); var list2 = new LinkedList(); arr1.forEach(function(key){ list1.append(key); }); arr2.forEach(function(key){ list2.append(key); }); var list = mergeLinkedList(list1, list2);
结果以下:
以上代码中,都省去了参数合法性校验的过程,真实环境里是须要的。