javascript实现数据结构:线性表--线性链表(链式存储结构)

上一节中, 线性表的顺序存储结构的特点是逻辑关系上相邻的两个元素在物理位置上也相邻,因此可以随机存取表中任一元素,它的存储位置可用一个简单,直观的公式来表示。然后,另一方面来看,这个特点也造成这种存储结构的弱点,在做插入或删除操作时,需移动大量元素

链式存储结构,由于它不需要逻辑上相邻的元素在物理位置上也相邻,因此它没有顺序存储结构所具有的弱点,但同时也失去了顺序表可随机存取的优点

 

线性链表

线性表的链式存储结构的特点是用一组任意的存储单元储存线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素a(i)与其直接后继数据元素a(i+1)之间的逻辑关系,对数据元素a(i)来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。这两部分信息组成数据元素a(i)的存储映像,称为结点(node)。它包括两个域:其中存储数据元素信息的域称为数据域;存储直接后继存储位置的域称为指针域,指针域中存储的信息称做指针

又由于此链表的每个结点中只包含一个指针域,故又称线性链表单链表

单链表的整个链表的存取必须从头指针开始进行,头指针指示链表中第一个结点(即第一个数据元素的存储映像)的存储位置。

同时,由于最后一个数据元素没有直接后继,则线性链表中最后一个结点的指针为空null。

1 // 线性表的单链表存储结构
2 function LNode(data, node) {
3   this.data = data;
4   this.next = node || null;
5 }

假设p是指向线性表中第i个数据元素(结点a(i))的指针,则p->next是指向第i+1个数据元素(结点a(i+1))的指针。

下面我们来看GetElem在单链表中的实现:

 1 function getElem(i) {
 2     // 初始化,p指向第一个节点,j为计数器
 3     var p = this.next;
 4     var j = 1;
 5     // 顺指针向后查找,知道p指向第i个元素或p为空
 6     while (p && j < i) {
 7       p = p.next;
 8       ++j;
 9     }
10     // 第i个元素不存在
11     // 或者取第i个元素
12     return (!p || j > i) ? null : p.data;
13   }

 

单链表的基本操作:

假设我们在线性表的两个数据元素a和b之间插入一个数据元素x,已知p为其单链表存储结构中指向结点a的指针。

插入:

假设s为指向结点x的指针,则可用语句描述:s->next = p->next;  p->next = s;

删除:

假设p为指向结点a的指针,则修改指针的语句为: p->next = p->next->next;

实现:

 1 function listInsert(i, data) {
 2     var j = 0;
 3     var p = this;
 4     // 寻找第i-1个节点
 5     while (p && j < i - 1) {
 6       p = p.next;
 7       ++j;
 8     }
 9     // i < 1或者大于表长+1
10     if (!p || j > i - 1) return false;
11     // 生成新节点,插入p节点后面
12     p.next = new LNode(data, p.next);
13     return true;
14   }
15 
16 function listDelete(i) {
17     var j = 0;
18     var p = this;
19 
20     while (p.next && j < i - 1) {
21       p = p.next;
22       ++j;
23     }
24 
25     if (!p.next || j > i - 1) return false;
26     var q = p.next;
27     p.next = q.next;
28     return q.data;
29   }

 

单链表的其他操作

 

逆位序输入n个元素的值,建立带表头结点的单链线性表L。

function createList_L(n) {
  var deferred = require(‘rsvp‘).defer();
  var l = new LNode();
  var count = n;
  process.stdin.setEncoding(‘utf8‘);

  process.stdin.on(‘data‘, function handler(data) {
    console.log(123);
    data = data.replace(‘\n‘, ‘‘);
    l.next = new LNode(data, l.next);
    if (!(--count)) {
      console.log(‘pausing‘);
      process.stdin.pause();
      deferred.resolve(l);
    }
  });

  return deferred.promise;
}

 

假设头指针为La和Lb的单链表分别为线性表LA和LB的存储结构,先要归并La和Lb得到单链表Lc:

 1 function mergeList(a, b) {
 2   var pa = a.next;
 3   var pb = b.next;
 4   // 用a的头结点作为c的头结点
 5   var c = a;
 6   var pc = a;
 7 
 8   while (pa && pb) {
 9     if (pa.data <= pb.data) {
10       pc.next = pa;
11       pc = pa;
12       pa = pa.next;
13     } else {
14       pc.next = pb;
15       pc = pb;
16       pb = pb.next;
17     }
18   }
19 
20   // 插入剩余段
21   pc.next = pa ? pa : pb;
22 
23   return c;
24 }

 

 

完整代码:

  1 // 单链表
  2 /*
  3 线性链表存储结构
  4 整个链表的存取必须从头指针开始进行,头指针指示链表中第一个结点(即第一个数据元素的存储映像)的存储位置。
  5 同时,由于最后一个数据元素没有直接后继,则线性链表中最后一个结点的指针为空null。
  6 */
  7 
  8 function LNode(data, node) {
  9   this.data = data;
 10   this.next = node || null;
 11 }
 12 LNode.prototype = {
 13   // 时间复杂度O(n)
 14   getElem: function getElem(i) {
 15     // 初始化,p指向第一个节点,j为计数器
 16     var p = this.next;
 17     var j = 1;
 18     // 顺指针向后查找,知道p指向第i个元素或p为空
 19     while (p && j < i) {
 20       p = p.next;
 21       ++j;
 22     }
 23     // 第i个元素不存在
 24     // 或者取第i个元素
 25     return (!p || j > i) ? null : p.data;
 26   },
 27   // 时间复杂度O(n)
 28   listInsert: function listInsert(i, data) {
 29     var j = 0;
 30     var p = this;
 31     // 寻找第i-1个节点
 32     while (p && j < i - 1) {
 33       p = p.next;
 34       ++j;
 35     }
 36     // i < 1或者大于表长+1
 37     if (!p || j > i - 1) return false;
 38     // 生成新节点,插入p节点后面
 39     p.next = new LNode(data, p.next);
 40     return true;
 41   },
 42   listDelete: function listDelete(i) {
 43     var j = 0;
 44     var p = this;
 45 
 46     while (p.next && j < i - 1) {
 47       p = p.next;
 48       ++j;
 49     }
 50 
 51     if (!p.next || j > i - 1) return false;
 52     var q = p.next;
 53     p.next = q.next;
 54     return q.data;
 55   }
 56 };
 57 
 58 LNode.createList_L = function createList_L(n) {
 59   var deferred = require(‘D:\\node\\node_modules\\rsvp‘).defer();
 60   var l = new LNode();
 61   var count = n;
 62   process.stdin.setEncoding(‘utf8‘);
 63 
 64   process.stdin.on(‘data‘, function handler(data) {
 65     console.log(123);
 66     data = data.replace(‘\n‘, ‘‘);
 67     l.next = new LNode(data, l.next);
 68     if (!(--count)) {
 69       console.log(‘pausing‘);
 70       process.stdin.pause();
 71       deferred.resolve(l);
 72     }
 73   });
 74 
 75   return deferred.promise;
 76 };
 77 
 78 function deepCopy(obj) {
 79   var newObj = {};
 80 
 81   for (var i in obj) {
 82     if (typeof obj[i] === ‘object‘) {
 83       newObj[i] = deepCopy(obj[i]);
 84     } else {
 85       newObj[i] = obj[i];
 86     }
 87   }
 88 
 89   return newObj;
 90 }
 91 
 92 // TODO
 93 /*
 94 已知单链线性表a和b的元素按值非递减排列。
 95 归并a和b得到新的单链线性表c,c的元素也按值非递减排列。
 96 */
 97 LNode.mergeList = function mergeList(a, b) {
 98   var pa = a.next;
 99   var pb = b.next;
100   // 用a的头结点作为c的头结点
101   var c = a;
102   var pc = a;
103 
104   while (pa && pb) {
105     if (pa.data <= pb.data) {
106       pc.next = pa;
107       pc = pa;
108       pa = pa.next;
109     } else {
110       pc.next = pb;
111       pc = pb;
112       pb = pb.next;
113     }
114   }
115 
116   // 插入剩余段
117   pc.next = pa ? pa : pb;
118 
119   return c;
120 };
121 
122 function log(list) {
123   var arr = [];
124 
125   do {
126     arr.push(list.data);
127     list = list.next;
128   } while (list);
129 
130   console.log(arr.join(‘,‘));
131 }
132 
133 void function test() {
134   var a1 = new LNode(1);
135   a1.listInsert(1, 2);
136   a1.listInsert(2, 3);
137   a1.listInsert(1, 4);
138   console.log(a1.getElem(1));
139   console.log(a1);
140   log(a1);
141   a1.listDelete(1);
142   console.log(‘a1 linkList:‘);
143   console.log(a1);
144   log(a1);
145   /*
146       LNode.createList_L(5)
147         .then(function(list){
148           console.log(list);
149         });
150       */
151   var a2 = new LNode(3);
152   a2.listInsert(1, 3);
153   a2.listInsert(2, 8);
154   a2.listInsert(1, 4);
155   a2.listDelete(2);
156   console.log(‘a2 linkList‘);
157   log(a2);
158 
159   var a3 = LNode.mergeList(a2, a1);
160   console.log(‘merging linkLists‘);
161   console.log(a3);
162   log(a3);
163 }();
View Code

 

 

javascript实现数据结构:线性表--线性链表(链式存储结构),古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。