数据结构学习:线性表

定义:

  表示n个相同类型的数据元素的有限集合。

线性表的主要操作有:

  (1)初始化   (2)求长度  (3)取元素              (4)定位

  (5)插入    (6)删除     (7)判断表是否为空  (8)表清空

存储方式:

  1.顺序存储方式  2.链式存储方式

 

1.先是顺序存储方式:

  1.1所谓顺序存储方式是值用一块地址连续的有限空间来存放表中的数据元素,任意两个逻辑上相邻的数据元素在物理内存上也必然是相邻的。

这边本人使用C++来实现顺序表,一般顺序表的实现有动态数组和静态数组两种方式:

  1.2静态数组实现起来比较简单,具体代码如下:

ContractedBlock.gif ExpandedBlockStart.gif 线性表顺序存储方式(静态数组)
1 /* ********************************
2 **sequencelist.h
3 **作者:Hazi
4 **时间:2011-7-12
5 **线性表顺序存储方式板类实现
6 **编译环境:VS2010,WindowsXP SP3
7 ******************************** */
8 #include < iostream >
9 using namespace std;
10 #define MAXSIZE 20 /*最大长度*/
11 template < class type > class sequencelist{
12 public :
13 sequencelist();
14 int Length() const ; /* 获取当前表长度 */
15 type Get( int i) const ; /* 获取表中第i个元素 */
16 int Locate( const type & item) const ; /* 定位表中第一个出现值为item的元素位置,不存在返回-1 */
17 bool InsertAfter
18 ( const type & item, int i); /* 在第i个元素之前插入值为item的元素 */
19 type Delete( const int i); /* 删除第i个元素,并返回删除的元素 */
20 bool Isempty() const ; /* 判断当前表是否为空 */
21 void Clear(); /* 清空表 */
22 private :
23 type _data[MAXSIZE]; /* 存放元素的数组 */
24 int _len; /* 线性表当前长度 */
25 };
26
27 template < class type >
28 sequencelist < type > ::sequencelist(){
29 this -> _len = 0 ;
30 }
31
32 template < class type >
33 int sequencelist < type > ::Length() const {
34 return this -> _len;
35 }
36
37 template < class type >
38 type sequencelist < type > ::Get( int i) const {
39 if (i < 1 || i > this -> _len){
40 cerr << " 表索引超出范围!\n " ;
41 exit( 1 );
42 }
43 return this -> _data[i - 1 ];
44 }
45
46 template < class type >
47 bool sequencelist < type > ::InsertAfter( const type & item, int i){
48 if (i < 0 || i > this -> _len){
49 cerr << " 表索引超出范围!\n " ;
50 return false ;
51 }
52 if ( this -> _len == MAXSIZE){
53 cerr << " 表已满!\n " ;
54 return false ;
55 }
56 /* 数组位移,向后移动_len-i位 */
57 memcpy( & this -> _data[i + 1 ], & this -> _data[i],( this -> _len - i) * sizeof (type));
58 this -> _data[i] = item;
59 this -> _len ++ ;
60 return true ;
61 }
62
63 template < class type >
64 type sequencelist < type > ::Delete( const int i){
65 if (i < 1 || i > this -> _len){
66 cerr << " 表索引超出范围!\n " ;
67 exit( 1 );
68 }
69 type tmp = this -> _data[i - 1 ];
70 /* 数组位移,向前移动_len-i位 */
71 memcpy( & this -> _data[i - 1 ], & this -> _data[i],( this -> _len - i) * sizeof (type));
72 this -> _len -- ;
73 return tmp;
74 }
75
76 template < class type >
77 bool sequencelist < type > ::Isempty() const {
78 return this -> _len == 0 ;
79 }
80
81 template < class type >
82 void sequencelist < type > ::Clear(){
83 this -> _len = 0 ;
84 }
85
86 template < class type >
87 int sequencelist < type > ::Locate( const type & item) const {
88 for ( int i = 0 ;i < this -> _len;i ++ )
89 if ( this -> _data[i] == item)
90 return i + 1 ;
91 return - 1 ;
92 }

  1.3下面讨论一下线性表插入删除时的算法复杂度:

  已知有如下一个顺序表:

  1  2  3  4  5

          ↑9

现在要在2之后插入一个新的元素9,则后三位3,4,5必须分别向后移一位。

计算一个元素个数为n的顺序表的插入数据时的平均移动个数:E=n+1i=1 1/(n+1)*(n-i+1)=n/2;

同理删除一个元素的平均移动个数:E=n+1i=1 1/n*(n-i)=(n-1)/2;

 2.下面来看看线性表的链式存储表示:

  2.1先看链表的结点:

  一种是较为简单的单向链表的结点

    data//存放具体元素  next//指向下一结点的指针

  还有一种双向链表的结点如下:

  prior//指向上一个结点  data//存放具体元素  next//指向下一结点的指针

  然后具体说一下,链表具体划分的性质包括:

  1.双向链表或单向链表

  2.带头结点的或不带头结点的

  3.单向链表或循环链表

  针对第1点的区别上面的结点示意图中已经很清楚了:

  针对第2点带不带头结点,这里简单叙述一下,不深入说了。之所以要这么区分是因为链表在插入操作的时候不带头结点的插入第一个元素的情况会较带头结点的多一种,为了简化情况就在原来的基础上添加了一个data为空的头结点作为头结点实现统一。还有一点就是带头结点的链表在循环链表中的指针的第一个结点的next指针和最后一个结点prior指针可以统一得指向head结点。

  针对第3点其实两者的区别就是最后一个元素的next指针(prior指针,如果存在)指向head头结点(或链表中最后一个元素,是具体带头结点与否而定)。

  2.2不多说了,贴段代码:

ContractedBlock.gif ExpandedBlockStart.gif 单向链表(带头结点,非循环)
1 /* ************************************
2 **linklist.h
3 **作者:Hazi
4 **时间:2011-7-12
5 **单项链表模板类实现,链表类
6 **编译环境:VS2010,WindowsXP SP3
7 ************************************ */
8 #include < iostream >
9 using namespace std;
10 template < class type > class linklist;
11 template < class type > class node{
12 friend class linklist < type > ; /* 设置友元,操作私有成员 */
13 public :
14 node(node < type >* next = NULL);
15 node( const type & data,node < type >* next = NULL);
16 ~ node(){}
17 void setNext(node < type > * p){ /* 设置下一个指向结点 */
18 this -> next = p;
19 }
20 void setData(type x){ /* 设置当前元素 */
21 this -> data = x;
22 }
23 private :
24 type data; /* 存放元素 */
25 node < type >* next; /* next指针 */
26 };
27
28 template < class type > class linklist{
29 public :
30 linklist( void );
31 ~ linklist();
32 int Length( void ) const ; /* 获取返回单链表长度 */
33 type GetCurrent() const ; /* 获取当前结点中的值 */
34 node < type >* Locate(type & x); /* 遍历链表找出第一个出现值为x的结点设为当前结点,不存在则返回NULL */
35 void InsertBefore( const type & x); /* 将值x插入当前结点之前,并将插入结点设为当前结点 */
36 void InsertAfter( const type & x); /* 将值x插入当前结点之后,并将插入结点设为当前结点 */
37 type DeleteCurrent(); /* 删除当前结点,并返回删除的结点指针 */
38 int Isempty() const ; /* 判断链表是否为空,返回1表示为空,0表示为非空 */
39 void Clear(); /* 清空当前链表 */
40 node < type >* Reset( int i); /* 重置链表的当前指针,使其指向第i个元素,并返回结点指针 */
41 node < type >* Next(); /* 使当前结点指向下一个结点 */
42 int EndOflinklist() const ; /* 判断是否已到表尾,1表示到表尾,0表示未到 */
43 void Freelinklist(); /* 释放链表 */
44 private :
45 node < type >* head; /* 头指针 */
46 node < type >* pcurrent; /* 当前结点指针 */
47 };
48
49 /* *****************************具体实现**************************** */
50 template < class type > node < type > ::node(node < type >* pnext){
51 this -> next = pnext;
52 }
53
54 template < class type > node < type > ::node( const type & item,node < type > * pnext){
55 this -> data = item;
56 this -> next = pnext;
57 }
58
59 template < class type >
60 int linklist < type > ::Length() const {
61 int length = 0 ;
62 node < type >* p = this -> head;
63 while (p != NULL){
64 length ++ ;
65 p = p -> next;
66 }
67 return length;
68 }
69
70 template < class type >
71 type linklist < type > ::GetCurrent() const {
72 return this -> pcurrent -> data;
73 }
74
75 template < class type >
76 node < type >* linklist < type > ::Locate(type & x){
77 node < type >* p = this -> head;
78 while (p != NULL){
79 if (p -> data == x){
80 this -> pcurrent = p;
81 return p;
82 }
83 p = p -> next;
84 }
85 return NULL;
86 }
87
88 template < class type >
89 void linklist < type > ::InsertBefore( const type & x){
90 node < type >* p = this -> head;
91 if ( this -> head == this -> pcurrent){
92 this -> head = new node < type > (x);
93 this -> head -> next = this -> pcurrent;
94 this -> pcurrent = this -> head;
95 }
96 else {
97 while (p -> next != this -> pcurrent){
98 p = p -> next;
99 }
100 p -> next = new node < type > (x);
101 p -> next -> next = this -> pcurrent;
102 this -> pcurrent = p -> next;
103 }
104 }
105
106 template < class type >
107 void linklist < type > ::InsertAfter( const type & x){
108 if ( this -> pcurrent -> next == NULL){
109 this -> pcurrent -> next = new node < type > (x);
110 this -> pcurrent = this -> pcurrent -> next;
111 }
112 else {
113 this -> pcurrent -> next = new node < type > (x, this -> pcurrent -> next);
114 this -> pcurrent = this -> pcurrent -> next;
115 }
116 }
117
118 template < class type >
119 linklist < type > ::linklist( void ){
120 this -> pcurrent = this -> head = new node < type > ();
121 this -> head -> next = NULL;
122 }
123
124 template < class type >
125 type linklist < type > ::DeleteCurrent(){
126 if ( this -> pcurrent == this -> head || this -> pcurrent == NULL){
127 cerr << " 不可删! " ;
128 exit( 1 );
129 }
130 node < type >* p = this -> head;
131 while (p -> next != this -> pcurrent){
132 p = p -> next;
133 }
134 p -> next -> next = this -> pcurrent -> next;
135 type value = this -> pcurrent -> data;
136 this -> pcurrent = this -> pcurrent -> next;
137 return value;
138 }
139
140 template < class type >
141 int linklist < type > ::Isempty() const {
142 return this -> head -> next == NULL ? 1 : 0 ;
143 }
144
145 template < class type >
146 void linklist < type > ::Clear(){
147 node < type >* p = this -> head;
148 node < type >* q;
149 while (p != NULL){
150 q = p;
151 p = p -> next;
152 delete q;
153 }
154 this -> pcurrent = this -> head;
155 }
156
157 template < class type >
158 node < type >* linklist < type > ::Reset( int i){
159 if ( this -> head == NULL || i < 0 )
160 return NULL;
161 node < type >* p = this -> head;
162 while (i --&& p != NULL){
163 p = p -> next;
164 }
165 if (p != NULL){
166 this -> pcurrent = p;
167 return p;
168 }
169 return NULL;
170 }
171
172 template < class type >
173 node < type >* linklist < type > ::Next(){
174 if ( this -> pcurrent == NULL)
175 return NULL;
176 else {
177 this -> pcurrent = this -> pcurrent -> next;
178 return this -> pcurrent;
179 }
180 }
181
182 template < class type >
183 int linklist < type > ::EndOflinklist() const {
184 return this -> pcurrent -> next == NULL ? 1 : 0 ;
185 }
186
187 template < class type >
188 void linklist < type > ::Freelinklist(){
189 node < type >* p,q;
190 p = this -> head;
191 while (p != NULL){
192 q = p;
193 p = p -> next;
194 delete q;
195 }
196 }
197
198 template < class type >
199 linklist < type > :: ~ linklist(){
200 node < type >* p = this -> head;
201 node < type >* q;
202 while (p != NULL){
203 q = p;
204 p = p -> next;
205 delete q;
206 }
207 }

  2.3具体的双向循环链表也是大同小异,可以修改部分实现,这里就不一一实现了。

  补充:当然线性表的实现方式不只上述两种,还有静态链表,一种咋看类似于顺序表的表示方式,个人感觉静态类表基本可以归入链表的行列,区别在于实现方式不是通过指针而是采用数组。目的是针对顺序表中的元素插入和删除复算法杂度高的缺点,为每一个元素添加了一个链接指针,这样做实现了类似于线性表的链式存储插入删除快速的优点,但与此同时要付出牺牲存储空间的代价。

由于要考研了,必须认真复习数据结构。就想到了有空就写一下,有利于归纳总结,文中可能出现错误,请各位大牛们不吝赐教啊,感激不尽啊,真心求赐教啊!!!!  

转载于:https://www.cnblogs.com/Hazi/archive/2011/07/13/2104776.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值