2-线性表 链式存储-单链表

想起大二笨笨的,很仔细地扣每个代码每个函数的细节,精确到用‘&’还是用‘*’

把所有自己不明白的函数都搜了一遍

硬着头皮去看,自己也没有学多好。

链表刚学的时候弄了自己两三天

明明是很简单的内容

我大概太笨,理解能力不好,学习方法也不好

但昨晚居然一个小时内哼哧哼哧写出来了

也许是很微小的事情,很微小的细节

也许第二次重新做的时候比第一次快了只有几分钟 至少真的进步了

加油,硬着头皮干,大家都是这么过来的

1、单链表基本功能的实现

  1 #include<iostream>
  2 #include<cstdlib>
  3 using namespace std;
  4 #define ture 1
  5 #define false 0
  6 #define maxsize 50
  7 #define listincreament 10
  8 #define ok 1
  9 #define error -3
 10 #define overflow -2
 11 typedef int Status;
 12 typedef int ElemType;
 13 typedef struct LNode
 14 {
 15     ElemType data;
 16     struct LNode *next;
 17 } LNode,*LinkList;
 18 //头插法建单链表
 19 void CreatList_head(LinkList &L,int length)//头插法
 20 {
 21     LNode *s;
 22     int x;
 23     L=(LinkList)malloc(sizeof(LNode));
 24     L->next=NULL;//创建头结点
 25     while(length--)
 26     {
 27         cin>>x;
 28         s=(LNode *)malloc(sizeof(LNode));
 29         s->data=x;
 30         s->next=L->next;
 31         L->next=s;
 32     }
 33 
 34 }
 35 void CreatList_tail(LinkList &L,int length)//尾插法
 36 {
 37     LNode *p,*s;
 38     int x;
 39     L=(LinkList)malloc(sizeof(LNode));
 40     L->next=NULL;
 41     p=L;
 42     while(length--)
 43     {
 44         cin>>x;
 45         s=(LNode *)malloc(sizeof(LNode));
 46         s->data=x;
 47         p->next=s;
 48         s->next=NULL;
 49         p=p->next;
 50     }
 51 }
 52 
 53 LNode* GetElem_order(LinkList &L,int n)//按序号查找节点
 54 {
 55     LNode *p=L;
 56     while(p!=NULL&&n>0)
 57     {
 58         p=p->next;
 59         n--;
 60     }
 61     return p;
 62 }
 63 LNode* GetElem_data(LinkList &L,ElemType e)//按值查找节点
 64 {
 65     LNode *p=L;
 66     while(p!=NULL&&p->data!=e)
 67         p=p->next;
 68     return p;
 69 }
 70 void InsertLNode(LinkList &L,ElemType elem,int pos)
 71 {
 72     LNode *p=L,*s;
 73     pos--;
 74     while(pos>0)
 75     {
 76         p=p->next;
 77         pos--;
 78     }
 79     s=(LNode *)malloc(sizeof(LNode));
 80     s->data=elem;
 81     s->next=p->next;
 82     p->next=s;
 83 }
 84 void InsertLNode2(LinkList &L,ElemType elem,int pos)
 85 {
 86     LNode *p=L,*s;
 87     while(pos>0)
 88     {
 89         p=p->next;
 90         pos--;
 91     }
 92     s=(LNode *)malloc(sizeof(LNode));
 93     s->data=elem;
 94     s->next=p->next;
 95     p->next=s;
 96     swap(p->data,s->data);
 97 }
 98 //书上介绍的一种方法,将s直接插入到第pos个节点的后面,再交换两个值。。
 99 void DeleteList_order(LinkList &L,int pos)//删除指定序号的节点
100 {
101     LNode *p=GetElem_order(L,pos-1);
102     LNode *q=p->next;
103     p->next=q->next;
104     free(q);
105 }
106 void DeleteList_data(LinkList &L,ElemType elem)//删除指定值的节点
107 {
108     LNode *p=GetElem_data(L,elem);
109     if(p->next!=NULL)//如果p不是最后一个节点,交换p和p下一个节点的值,删除p的下一个节点(逻辑上等同于删除p
110     {
111         LNode *q=p->next;
112         swap(q->data,p->data);
113         p->next=q->next;
114         free(q);
115     }
116     else free(p);//如果p是最后一个节点,那么可以直接删除p。
117 }
118 int showlength(LinkList L)//求表长。
119 {
120     int length=0;
121     while(L->next!=NULL)
122     {
123         length++;
124         L=L->next;
125     }
126     return length;
127 }
128 void showList(LinkList &L)
129 {
130     LNode *p=L->next;
131     while(p!=NULL)
132     {
133         cout<<p->data;
134         if(!(p->next==NULL))
135         {
136             cout<<' ';
137         }
138         p=p->next;
139     }
140     cout<<endl;
141 }
142 void showpoint(LNode *p)//展示特定节点的信息
143 {
144     if(p!=NULL)
145         cout<<p->data<<endl;
146     else cout<<"not found."<<endl;
147 }
148 
149 //注意:因为生成链表的时候第一个节点是跟在L的后面,即L本身是不存储信息的。
150 //故在按照链表的顺序输出元素值的时候,工作指针p一开始应该指向第一个节点(即L->next)
151 int main()
152 {
153     LNode *L1,*L2,*pos;
154     CreatList_head(L1,10);
155     CreatList_tail(L2,7);
156     showList(L1);
157     showList(L2);
158     pos=GetElem_order(L2,4);
159     showpoint(pos);
160     pos=GetElem_data(L2,99);
161     showpoint(pos);
162     InsertLNode(L1,10,6);
163     InsertLNode2(L2,100,5);
164     showList(L1);
165     showList(L2);
166 
167     DeleteList_order(L1,2);
168     DeleteList_data(L2,100);
169     cout<<"After delete some elem:"<<endl;
170     showList(L1);
171     showList(L2);
172     cout<<"Show the length of linklist:L1 is "<<showlength(L1)<<",while L2 is "<<showlength(L2)<<"."<<endl;
173 }

 2、单链表的一些小功能算法实现:

(1)【来源】王道书本题1~7

  1 /*-----------------算法设计-----------------*/
  2 /*递归算法,删除不带头结点的单链表x中所有值为x的节点*/
  3 /*终止条件:L为空表,不作任何事*/
  4 /*递归主体:如果L->data为x ~ delete_X(L->next,x)*/
  5 void delete_X(LinkList &L,ElemType x)
  6 {
  7     LNode *p;
  8     if(L==NULL) return ;
  9     if(L->data==x)
 10     {
 11         p=L;
 12         L=L->next;
 13         free(p);
 14         delete_X(L,x);
 15     }
 16     else delete_X(L->next,x);
 17 }
 18 /*带头结点的单链表中删除所有值为x的节点,释放空间。*/
 19 /*做法1:直接删除值为x的节点*/
 20 void delete_allX(LinkList &L,ElemType x)
 21 {
 22     LNode *p=L->next,*q,*r=L;
 23     while(p!=NULL)
 24     {
 25         if(p->data==x)
 26         {
 27             q=p;
 28             r->next=p->next;
 29             p=p->next;
 30             free(q);
 31         }
 32         else
 33         {
 34             p=p->next;
 35             r=r->next;
 36         }
 37     }
 38 }
 39 /*做法2:通过尾插法把data值非x的节点接入r->next*/
 40 void delelet_allX2(LinkList &L,ElemType x)
 41 {
 42     LNode *p=L->next,*r=L,*q;
 43     while(p!=NULL)
 44     {
 45         if(p->data!=x)
 46         {
 47             r->next=p;
 48             r=p;
 49             p=p->next;
 50         }
 51         else
 52         {
 53             q=p;
 54             p=p->next;
 55             free(q);
 56         }
 57     }
 58 }
 59 
 60 /*逆向输出链表的元素值*/
 61 /*用递归的思路实现*/
 62 void reverse_print(LinkList L)
 63 {
 64     if(L->next!=NULL) reverse_print(L->next);
 65     cout<<L->data<<' ';
 66 }
 67 //注:调用的时候,如果链表有头结点,调用的时候应该如此调用:reverse_print(L1->next);
 68 
 69 /*编写删除带头结点链表中值为最小的节点的高效算法*/
 70 void delete_mindata(LinkList &L)
 71 {
 72     LNode *p=L->next,*r=L;
 73     LNode *minr=r,*minp=p;
 74     while(p!=NULL)
 75     {
 76         if(p->data<minp->data)
 77         {
 78             minr=r;
 79             minp=p;
 80         }
 81         r=r->next;
 82         p=p->next;
 83     }
 84     minr->next=minp->next;
 85     free(minp);
 86 }
 87 /*逆置单链表,空间复杂度为O(1)*/
 88 /*头插法*/
 89 void reverse_LinkList(LinkList &L)
 90 {
 91     LNode *p=L->next,*r=L;
 92     L->next=NULL;
 93     while(p!=NULL)
 94     {
 95         r=p->next;
 96         p->next=L->next;
 97         L->next=p;
 98         p=r;
 99     }
100 }
101 /*指针翻转法*/
102 /*用笔模拟一下就很好理解了*/
103 void Reverse_LinkList2(LinkList &L)
104 {
105     LNode *r,*p=L->next,*q=p->next;
106     p->next=NULL;
107     while(q!=NULL)
108     {
109         r=p;
110         p=q;
111         q=q->next;
112         p->next=r;
113     }
114     L->next=p;
115 }
116 
117 /*对于带头链表L排序使之递增有序*/
118 /*头插法:找到第一个大于它的节点,用头插法插入链表*/
119 void sortLinkList(LinkList &L)
120 {
121     LNode *p,*q,*r;
122     p=L->next;
123     q=p->next;
124     p->next=NULL;
125     p=q;
126     while(p!=NULL)
127     {
128         q=q->next;
129         r=L;
130         while(r->next!=NULL&&r->next->data<p->data) r=r->next;
131 
132         //头插法插入链表L
133         p->next=r->next;
134         r->next=p;
135         p=q;
136     }
137 }
138 /*删除代表头节点的链表中值于给定两个元素之间的节点*/
139 int delete_lotsofe(LinkList &L,int a,int b)
140 {
141     if(b<a) return error;//a要>b
142     LNode *p=L->next,*r=L,*q;
143     while(p!=NULL)
144     {
145         if(p->data<b&&p->data>a)
146         {
147             q=p;
148             r->next=p->next;
149             p=p->next;
150             free(q);
151         }
152         else{
153             p=p->next;
154             r=r->next;
155         }
156     }
157 }

【注】

1、单链表运用头插法递增排序示意图

(2)【来源】王道书本题8~15

啊啊啊弄了一下午,美好下午就没有了!!!!!蓝瘦!!!!!!

我的线代复习大业啊!!

其中那个就地算法拆分线性表的还不好使,我要思考一下到底是啥问题……要是有大神知道了请告诉我orz

  1 /*寻找两个单链表的共同结点*/
  2 /*按自己的想法写了一下,让链表长度比较长的链表工作指针往后走到剩余长度与较短链表想同*/
  3 /*然后同时工作指针后移,找到第一个相同的结点(由于链表指针后序唯一性,剩下的结点肯定是一样的)*/
  4 LinkList Search_commonLNode(LinkList &a,LinkList &b)
  5 {
  6     LNode *p=a,*q=b;
  7     int numa=showlength(a),numb=showlength(b);
  8     if(numa>numb)
  9     {
 10         while(numa!=numb)
 11         {
 12             p=p->next;
 13             numa--;
 14         }
 15     }
 16     else if(numb>numb)
 17     {
 18         while(numb!=numa)
 19         {
 20             q=q->next;
 21             numb--;
 22         }
 23     }
 24     while(q!=p)
 25     {
 26         q=q->next;
 27         p=p->next;
 28     }
 29     return q;
 30 }
 31 /*不使用数组作为辅助空间,递增输出链表元素值并且输出同时释放链表结点*/
 32 void print_increase(LinkList &L)
 33 {
 34     LNode *p,*q,*r;
 35     while(L->next!=NULL)
 36     {
 37         q=L;
 38         p=L->next;
 39         while(p->next!=NULL)//参考点为后继元素,这里要用p->next
 40         {
 41             if(p->next->data<q->next->data)//每一次对比指向最小元素的前驱
 42                 q=p;
 43             p=p->next;
 44         }
 45         cout<<q->next->data<<" ";
 46         r=q->next;
 47         q->next=q->next->next;
 48         free(r);
 49     }
 50     //最后别忘记释放头结点
 51     free(L);
 52 }
 53 /*给定一个带头结点的单链表A,分解为两个带头结点的单链表A和B
 54 使得表A中含有原来序号为奇数的元素,表B含有原来序号为偶数的元素*/
 55 LinkList Discreate_1(LinkList &A)
 56 {
 57     int flag=1;
 58     LNode *B;
 59     B=(LinkList)malloc(sizeof(LNode));
 60     B->next=NULL;
 61     LNode *b,*a=A->next,*pb=B,*pa=A;
 62     A->next=NULL;
 63     while(a!=NULL)//原来想试着不使用flag标志,直接一次处理两个结点。后来捣鼓了半小时还是不对,敢情要针对A表长度奇偶性写两种情况……
 64         //为了赶时间还是放弃那么写了,还是这个直接断开A链表,重装A、B的方法逻辑上更简单粗暴
 65     {
 66         if(flag)
 67         {
 68             pa->next=a;
 69             pa=pa->next;
 70             flag=!flag;
 71         }
 72         else
 73         {
 74             pb->next=a;
 75             pb=pb->next;
 76             flag=!flag;
 77         }
 78         a=a->next;
 79     }
 80     pa->next=NULL;
 81     pb->next=NULL;
 82     return B;
 83 }
 84 /*设计一个就地算法把一个链表拆成两个线性表(a和b)*/
 85 /*c:a1,b1,a2,b2..*/
 86 /*卧槽,原来这个就是我所想的一次处理两元素……刚刚到底是哪里出错了啊啊!*/
 87 /*采用头插法插入结点后,p的指针域会改变,必须设置一个变量保存p的后继结点,不然会产生断链的问题!*/
 88 LinkList Discreate_2(LinkList &C)
 89 {
 90     LinkList B=(LinkList)malloc(sizeof(LNode));
 91     B->next=NULL;
 92     LNode *p=C->next;
 93     LNode *q,*c=C;
 94     while(p!=NULL)
 95     {
 96         c->next=p;
 97         c=p;
 98         p=p->next;
 99         q=p->next;//用q保存p的后继结点。
100         p->next=B->next;
101         B->next=p;
102         p=q;
103     }
104     c->next=NULL;
105     return B;
106 }
107 /*还是出错,这是为啥 这是为啥!!先跳过了*/
108 
109 /*递增有序链表去掉元素相同的结点*/
110 void delete_same(LinkList &L)
111 {
112     LNode *p=L->next,*pre=p,*q;
113     while(p->next!=NULL)
114     {
115         q=p->next;
116         if(p->data==q->data)
117         {
118             p->next=q->next;
119             free(q);
120         }
121         else p=p->next;
122     }
123 }
124 /*两个递增次序排列的线性表以单链表存储
125 试把两个单链表归并成一个按照元素值递减次序排列的单链表
126 存放在原来的结点
127 */
128 void mergeList_bydesc(LinkList &A,LinkList &B)
129 {
130     LNode *pa=A->next,*pb=B->next,*r;
131     A->next=NULL;
132     while(pa&&pb)
133     {
134         if(pa->data<pb->data)
135         {
136             r=pa->next;
137             pa->next=A->next;
138             A->next=pa;
139             pa=r;
140         }
141         else
142         {
143             r=pb->next;
144             pb->next=A->next;
145             A->next=pb;
146             pb=r;
147         }
148     }
149     if(pa)
150         pb=pa;
151     while(pb)
152     {
153         r=pb->next;
154         pb->next=A->next;
155         A->next=pb;
156         pb=r;
157     }
158 }
159 /*在不破坏A、B链表结点的情况下(递增有序),用公共元素生成新的单链表C*/
160 LinkList new_Cwithcommon_elem(LinkList &A,LinkList &B)
161 {
162     LNode *C,*pa=A->next,*pb=B->next,*r,*s;
163     C=(LinkList)malloc(sizeof(LNode));
164     r=C;
165     while(pa&&pb)
166     {
167         if(pa->data<pb->data)
168             pa=pa->next;
169         else if(pb->data<pa->data)
170             pb=pb->next;
171         else
172         {
173             s=(LNode *)malloc(sizeof(LNode));
174             s->data=pb->data;
175             r->next=s;
176             r=r->next;
177             pa=pa->next;
178             pb=pb->next;
179         }
180     }
181     r->next=NULL;
182     return C;
183 }
184 /*求AB链表的交集存于A中*/
185 /*思想其实是和上一个算法是基本一致的!但是别忘了用完了要把剩下的非空链表也释放空间*/
186 LinkList inersection(LinkList &A,LinkList &B)
187 {
188     LNode *pa=A->next,*pb=B->next,*r,*s;
189     r=A;
190     A->next=NULL;
191     while(pa&&pb)
192     {
193         if(pa->data<pb->data)
194         {
195             s=pa;
196             pa=pa->next;
197             free(s);
198         }
199         else if(pb->data<pa->data)
200 
201         {
202             s=pb;
203             pb=pb->next;
204             free(s);
205         }
206         else
207         {
208             r->next=pa;
209             r=r->next;
210             pa=pa->next;
211             s=pb;
212             pb=pb->next;
213             free(s);
214         }
215     }
216     if(pa)
217         pb=pa;
218     while(pb)
219     {
220         s=pb;
221         pb=pb->next;
222         free(s);
223     }
224     r->next=NULL;
225     return A;
226 }

 (8)【来源】王道书本题16~21(除去19题 19写在循环单链表里了。)

  1 /*两个整数序列a、b,判断b是否为a的子序列*/
  2 /*两个链表从第一个结点开始后移指针,如果不等,a从上次比较的后继开始,b从第一个节点开始比较*/
  3 /*如果A比较完了B没结束->失败*/
  4 
  5 int Pattern(LinkList &A,LinkList &B)
  6 {
  7     LNode *a=A->next,*pa=A,*b=B->next;
  8     while(a&&b)
  9     {
 10         if(a->data==b->data)
 11         {
 12             a=a->next;
 13             b=b->next;
 14         }
 15         else
 16         {
 17             pa=pa->next;
 18             a=pa->next;
 19             b=B->next;
 20         }
 21     }
 22     if(a==NULL&&b!=NULL)
 23         return 0;
 24     else return ok;
 25 }
 26 /*一带头结点循环单链表,节点值均为正数。设计一算法反复找出单链表中结点值最小的点,输出*/
 27 /*直至单链表为空,最后删除头结点。*/
 28 void del(LinkList &L)
 29 {
 30     LNode *p,*pre,*pmin,*minpre;
 31     while(L->next!=L)
 32     {
 33         p=L->next;
 34         pre=L;
 35         minpre=L;
 36         pmin=p;
 37         while(p->next!=pre)
 38         {
 39             if(p->data<pmin->data)
 40             {
 41                 pmin=p;
 42                 minpre=pre;
 43             }
 44             pre=p;
 45             p=p->next;
 46         }
 47         //找到了 删除最小结点
 48         cout<<pmin->data<<' ';
 49         minpre->next=pmin->next;
 50         free(pmin);
 51     }
 52     free(L);
 53 }
 54 
 55 /*一带头结点非循环单链表,每个节点中除了pred next还有freq(访问频度)*/
 56 /*链表启用前值均初始化为0,每链表Locate(L,x)一次,freq增一*/
 57 /*设计算法使得链表节点保持按照访问频度递减顺序排列,最近访问节点排于同一个节点频度的前面*/
 58 typedef struct LspNode
 59 {
 60     int data,freg;/*一带头结点循环单链表,节点值均为正数。设计一算法反复找出单链表中结点值最小的点,输出*/
 61     /*直至单链表为空,最后删除头结点。*/
 62     struct LspNode *next,*prior;
 63 } LspNode,*LinkspList;
 64 LinkspList Locate(LinkspList &L,int x)
 65 {
 66     LspNode *p,*q;
 67     while(p->data!=x&&p)
 68     {
 69         p=p->next;
 70     }
 71     if(!p)
 72     {cout<<"error"<<endl;exit(0);}//p不存在
 73     else
 74     {
 75         p->freg++;
 76         //漏掉了!把p摘掉还要对p前后结点进行处理,自己写的时候忘掉了
 77 
 78         q=p->prior;//递减排列,往前找第一个比他大的节点
 79         /*-----------*/
 80         p->next->prior=p->prior;
 81         p->prior->next=p->next;
 82         /*把p摘出来*/
 83         while(p->freg>q->freg&&q!=L)
 84             q=q->prior;
 85         //找到后插入到q的后面
 86         p->next=q->next;
 87         q->next->prior=p;
 88         p->prior=q;
 89         q->next=p;
 90     }
 91     return p;
 92 }
 93 
 94 /*在不改变链表前提下设计查找倒数第k个位置上的节点。查找成功输出data的值,返回1,否则返回0*/
 95 /*一开始一起指向表头,p先移动k个结点,然后p、q一向前移动。当p到了最后一个结点时,q为倒数第k个节点。*/
 96 /*ps:这个思路真是太聪明啦*/
 97 int findthe_kthlast_elem(LinkList &L,int k)
 98 {
 99     if(k>showlength(L)) return 0;
100     LNode *p=L,*q=L;
101     while(k--)
102     {
103         p=p->next;
104     }//p先走k个结点
105     while(p)
106     {
107         p=p->next;
108         q=q->next;
109     }//p走到最后的时候q为倒数第k个结点
110     cout<<q->data<<endl;
111     return 1;
112 }

 

链式存储的终于写完了 分了三天写

回头还是要看看 以后再来完善

写代码的时候常有“还有这种操作”的念头蹦出来

大概自己真是个鶸

 

posted @ 2017-07-12 12:27  -DP-  阅读(364)  评论(0编辑  收藏  举报