3-2试编写一个算法,在带表头结点的单链表中寻找第i个结点。若找到,则函数返回第i个结点的 地址;若找不到,则函数返回0 【解答】 template <class Type> LisiNode <Type>* List <Type>: GetANode( int i)i ∥取得单链表中第i个结点地址,i从0开始计数,i<0时返回指针0,i=0时返回表头结点地址。 if( i< 1)return NULL ListNode <Type>*p=first; int k=0; while(p I=NULL &&k<i)p=p-link; A++;1 return p; 3-3设ha和hb分别是两个带表头结点的非递减有序单链表的表头指针,试设计一个算法,将这两个 有序链表合并成一个非递增有序的单链表。要求结果链表仍使用原来两个链表的存储空间,不另外占 用其它的存储空间。表中允许有重复的数据。 【解答】 #include <iostream h> template <class Type> class List; template <class Type> class Lisinode friend class LisKType> ListNode (i ListNode( const Type& item ) ∥构造函数 private Type data; template <class Type> class List i List( const Type finishied ) ∥建立链表 void Browse ( ∥打印链表 void Merge( Lis/<Type>&hb ) ∥连接链表 rivate ListNode<Type ∥.成员函数的实现 template <class Type> LisiNode<Type>: LisiNode ( link( NULl)& ∥构造函数,仅初始化指针成员 template <class Type> ListNodesType>: ListNode( const Type item ): data( item ), link( NULL)
3-2 试编写一个算法,在带表头结点的单链表中寻找第 i 个结点。若找到,则函数返回第 i 个结点的 地址;若找不到,则函数返回 0。 【解答】 template <class Type> ListNode <Type> * List <Type> :: GetANode ( int i ) { //取得单链表中第 i 个结点地址, i 从 0 开始计数, i < 0 时返回指针 0, i = 0 时返回表头结点地址。 if ( i < 1 ) return NULL; ListNode <Type> * p = first; int k = 0; while ( p != NULL && k < i ) { p = p→link; k++; } return p; } 3-3 设 ha 和 hb 分别是两个带表头结点的非递减有序单链表的表头指针, 试设计一个算法, 将这两个 有序链表合并成一个非递增有序的单链表。要求结果链表仍使用原来两个链表的存储空间, 不另外占 用其它的存储空间。表中允许有重复的数据。 【解答】 #include <iostream.h> template <class Type> class List; template <class Type> class ListNode { friend class List<Type>; public: ListNode ( ); //构造函数 ListNode ( const Type& item ); //构造函数 private: Type data; ListNode<Type> *link; }; template <class Type> class List { public: List ( const Type finishied ); //建立链表 void Browse ( ); //打印链表 void Merge ( List<Type> &hb ); //连接链表 private: ListNode<Type> *first, *last; }; //各成员函数的实现 template <class Type> ListNode<Type>::ListNode ( ) : link ( NULL ) { } //构造函数, 仅初始化指针成员。 template <class Type> ListNode<Type> :: ListNode ( const Type & item ) : data ( item ), link ( NULL ) { }
∥构造函数,初始化数据与指针成员 template <class Type> LiskType>: List( const Type finishied ∥创建一个带表头结点的单链表, finished是停止建表输入的标志, ∥是所有输入值中不可能出现的数值 first last =new LisiNode<Type>( )i 建表头结点 Type walue; ListNode<Type>*p,*g,*s while walue I=finished)i 环建立各个结点 s= new LisINode<type>( ralue )i q=frst;p=frst→link; while(Pl=NULL&&p→da ∥寻找新结点插入位置 q→lik=s;s→lnk=p 在q,P间插入新结点 if(p==nUll)last=s cin >> value: template <class Type>void LisKType>:: Browse (i ∥浏览并输出链表的内容 cout<<nThe List is: \r Listooder<Type·p=fs→limk cout f(pl=at)cout<"→"; template <class Type> void List <Type>: Merge( LisK<Type>& hb) ∥将当前链表this与链表hb按逆序合并,结果放在当前链表this中。 ListNode<Type> 'pa, 'pb,'g, pa=first-link; pb =hb. fin ∥检测指针跳过表头结点 ∥结果链表初始化 while (pa I= NULL & pb I= NULL)i 当两链表都未结束时 {q=pa;p=p→lnk;} ∥从p链中摘下 从pb链中摘下 q→lik= first→link; first→link=q; ∥链入结果链的链头 }
//构造函数, 初始化数据与指针成员。 template <class Type> List<Type> :: List ( const Type finishied ) { //创建一个带表头结点的单链表,finished 是停止建表输入的标志, //是所有输入值中不可能出现的数值。 first = last = new ListNode<Type>( ); //创建表头结点 Type value; ListNode<Type> *p, *q, *s; cin >> value; while ( value != finished ) { //循环建立各个结点 s = new ListNode<Type>( value ); q = first; p = first→link; while ( p != NULL && p→data <= value ) { q = p; p = p→link; } //寻找新结点插入位置 q→link = s; s→link = p; //在 q, p 间插入新结点 if ( p == NULL ) last = s; cin >> value; } } template <class Type>void List<Type> :: Browse ( ) { //浏览并输出链表的内容 cout<<"\nThe List is : \n"; ListNode<Type> *p = first→link; while ( p != NULL ) { cout << p→data; if ( p != last ) cout << "→"; else cout << endl; p = p→link; } } template <class Type> void List <Type> :: Merge ( List<Type>& hb) { //将当前链表 this 与链表 hb 按逆序合并,结果放在当前链表 this 中。 ListNode<Type> *pa, *pb, *q, *p; pa = first→link; pb = hb.first→link; //检测指针跳过表头结点 first→link = NULL; //结果链表初始化 while ( pa != NULL && pb != NULL ) { //当两链表都未结束时 if ( pa→data <= pb→data ) { q = pa; pa = pa→link; } //从 pa 链中摘下 else { q = pb; pb = pb→link; } //从 pb 链中摘下 q→link = first→link; first→link = q; //链入结果链的链头 }
p=(pa I= NULL ) pa: pb; 处理未完链的剩余部分 while(p I= NULL )i q→link=irst→link;mrst→link=q; 3-6设有一个表头指针为h的单链表。试设计一个算法,通过遍历一趟链表,将链表中所有结点的链 接方向逆转,如下图所示。要求逆转结果链表的表头指针h指向原链表的最后一个结点。 h 【解答1】 template<class Type> void Lisk<Type>: Immerse ()i if(first== NULL)return; Listooder<Type>·p=fst→lik;,spr=NULL; ile(p I= NULL)i 逆转st指针 =p;p=p→link 指针前移 【解答2】 template<class Type> void Lis<<Type>: Inverse()i ListNode<Type> ' p, head new ListNode<Type>(; while (first I= NULL)& p=first; first =first-link 摘下fst链头结点 p→link=head→link;head→lnk=p;/插入head链前端 first head-link; delete head ∥重置fst 3-7从左到右及从右到左遍历一个单链表是可能的,其方法是在从左向右遍历的过程中将连接方向逆 转,如右图所示。在图中的指针p指向当前正在访问的结点,指针p指向指针p所指结点的左侧的结 点。此时,指针p所指结点左侧的所有结点的链接方向都已逆转 (1)编写一个算法,从任一给定的位置(pr,p)开始,将指针p右移k个结点。如果p移出链表,则 将p置为0,并让p停留在链表最右边的结点上。 (2)编写一个算法,从任一给定的位置(p,p)开始,将指针p左移k个结点。如果p移出链表,则 将p置为0,并让pr停留在链表最左边的结点上 【解答】 (1)指针p右移k个结点
p = ( pa != NULL ) ? pa : pb; //处理未完链的剩余部分 while ( p != NULL ) { q = p; p = p→link; q→link = first→link; first→link = q; } } 3-6 设有一个表头指针为 h 的单链表。试设计一个算法,通过遍历一趟链表,将链表中所有结点的链 接方向逆转,如下图所示。要求逆转结果链表的表头指针 h 指向原链表的最后一个结点。 【解答 1】 template<class Type> void List<Type> :: Inverse ( ) { if ( first == NULL ) return; ListNode<Type> *p = first→link;, *pr = NULL; while ( p != NULL ) { first→link = pr; //逆转 first 指针 pr = first; first = p; p = p→link; //指针前移 } } 【解答 2】 template<class Type> void List<Type> :: Inverse ( ) { ListNode<Type> *p, *head = new ListNode<Type> ( ); while ( first != NULL ) { p = first; first = first→link; //摘下 first 链头结点 p→link = head→link; head→link = p; //插入 head 链前端 } first = head→link; delete head; //重置 first } 3-7 从左到右及从右到左遍历一个单链表是可能的,其方法是在从左向右遍历的过程中将连接方向逆 转,如右图所示。在图中的指针 p 指向当前正在访问的结点,指针 pr 指向指针 p 所指结点的左侧的结 点。此时,指针 p 所指结点左侧的所有结点的链接方向都已逆转。 (1) 编写一个算法,从任一给定的位置(pr, p)开始,将指针 p 右移 k 个结点。如果 p 移出链表,则 将 p 置为 0,并让 pr 停留在链表最右边的结点上。 (2) 编写一个算法,从任一给定的位置(pr, p)开始,将指针 p 左移 k 个结点。如果 p 移出链表,则 将 p 置为 0,并让 pr 停留在链表最左边的结点上。 【解答】 (1) 指针 p 右移 k 个结点
template<class Type> void Lisk<Type> sifiToRight( ListNode<Type>*& p, ListNode<Type> * pr, int k)( f(p== null & pr I=first)i ∥已经在链的最右端 cout<<"已经在链的最右端,不能再右移。”<<endl; return int i; ListNode<Type>*q if(P== NULL ∥从链头开始 p=firs; 3 ∥重置p到链头也算一次右移 hile(p l=NULL &&i<k)i ∥右移k个结点 q=p→link;p→link=pr; ∥链指针p→lmk逆转指向pr pr=p;p=q;汁+; ∥指针pr,p右移 cout<<"右移了"<<i<<"个结点。"<<endl; (2)指针p左移k个结点 template<class Type> void Lisk<Type> sifiToLefi( ListNode<Type>*& p, LisnNode<type>*& pr, int k)& if (p== NULL & pr==first )t ∥已经在链的最左端 cout<<"已经在链的最左端,不能再左移。”<<endl int i=0; ListNode<type>*q; while (pr l=NULL &&i<k)i ∥左移k个结点 q=pr→lnk;pr→link=p; ∥链指针p→lmk逆转指向p 指针 左移 cout<<"左移了”<<i<<"个结点。”<<endl; if (i<k)ipr=p; P=NULL; 3 ∥指针p移出表外,重置p,P 3-9试写出用单链表表示的字符串类及字符串结点类的定义,并依次实现它的构造函数、以及计算串 长度、串赋值、判断两串相等、求子串、两串连接、求子串在串中位置等7个成员函数。要求每个字 符串结点中只存放一个字符 【解答】 ∥用单链表表示的字符串类smg1的头文件 stringl. h const int maxLen = 300: ∥字符串最大长度为300(理论上可以无限长) class stringl i stringl ( ∥构造空字符串 ringl( char *obstr ) ∥从字符数组建立字符串 stringl ( ∥析构函数
template<class Type> void List<Type> :: siftToRight ( ListNode<Type> *& p, ListNode<Type> *& pr, int k ) { if ( p == NULL && pr != first ) { //已经在链的最右端 cout << "已经在链的最右端,不能再右移。" << endl; return; } int i; ListNode<Type> *q; if ( p == NULL ) //从链头开始 { i = 1; pr = NULL; p = first; } //重置 p 到链头也算一次右移 else i = 0; while ( p != NULL && i < k ) { //右移 k 个结点 q = p→link; p→link = pr; //链指针 p→link 逆转指向 pr pr = p; p = q; i++; //指针 pr, p 右移 } cout << "右移了" << i << "个结点。" << endl; } (2) 指针 p 左移 k 个结点 template<class Type> void List<Type> :: siftToLeft ( ListNode<Type> *& p, ListNode<Type> *& pr, int k ) { if ( p == NULL && pr == first ) { //已经在链的最左端 cout << "已经在链的最左端,不能再左移。" << endl; return; } int i = 0; ListNode<Type> *q; while ( pr != NULL && i < k ) { //左移 k 个结点 q = pr→link; pr→link = p; //链指针 pr→link 逆转指向 p p = pr; pr = q; i++; //指针 pr, p 左移 } cout << "左移了" << i << "个结点。" << endl; if ( i < k ) { pr = p; p = NULL; } //指针 p 移出表外,重置 p, pr } 3-9 试写出用单链表表示的字符串类及字符串结点类的定义,并依次实现它的构造函数、以及计算串 长度、串赋值、判断两串相等、求子串、两串连接、求子串在串中位置等 7 个成员函数。要求每个字 符串结点中只存放一个字符。 【解答】 //用单链表表示的字符串类 string1 的头文件 string1.h #include <iostream.h> const int maxLen = 300; //字符串最大长度为 300(理论上可以无限长) class string1 { public: string1 ( ); //构造空字符串 string1 ( char * obstr ); //从字符数组建立字符串 ~string1 ( ); //析构函数
int Length() const{ return curLen;}∥求字符串长度 ∥串赋值 int operator ==( string I& ob ) ∥判两串相等 char& operator [ int i); 取串中字符 取子串 stringl& operator += string l& ob ) int Find( string l& ob ); ∥求子串在串中位置(模式匹配) friend ostream& operator << ostream& os, stringl& ob )i friend istream& operator >> istream& is, string l& ob )i ListNodeschar>schist: ∥用单链表存储的字符串 int curLen; ∥当前字符串长度 ∥单链表表示的字符串类 string l成员函数的实现,在文件 string1.cpp中 #include <iostream h> lh" string l∷; string l(){ ∥构造函数 chlist=new ListNodeschar>(0); stringl : stringl( char * obstr )i 复制构造函数 Len =0 ListNodeschar *p= chlist new ListNodechar>(*obstr ) while(*obstr I=0)i obstr++ p=p-link new ListNode<char>(*obstr )i curLen++; string I& stringl : operator = stringl& ob)i 串赋值 ListNodeschar> *a= chlist new ListNodeschar(p-data ) while(p→ data=vo){ q=q→lnk= new ListNode<char>(p→da); return *this int stringl operator == string l& ob)i 判两串相等
int Length ( ) const { return curLen; }//求字符串长度 string1& operator = ( string1& ob ); //串赋值 int operator == ( string1& ob ); //判两串相等 char& operator [ ] ( int i ); //取串中字符 string1& operator ( ) ( int pos, int len ); //取子串 string1& operator += ( string1& ob ); //串连接 int Find ( string1& ob ); //求子串在串中位置(模式匹配) friend ostream& operator << ( ostream& os, string1& ob ); friend istream& operator >> ( istream& is, string1& ob ); private: ListNode<char>*chList; //用单链表存储的字符串 int curLen; //当前字符串长度 } //单链表表示的字符串类 string1 成员函数的实现,在文件 string1.cpp 中 #include <iostream.h> #include "string1.h" string1 :: string1( ) { //构造函数 chList = new ListNode<char> ( '\0' ); curLen = 0; } string1 :: string1( char *obstr ) { //复制构造函数 curLen = 0; ListNode<char> *p = chList = new ListNode<char> ( *obstr ); while ( *obstr != '\0' ) { obstr++; p = p→link = new ListNode<char> ( *obstr ); curLen++; } } string1& string1 :: operator = ( string1& ob ) { //串赋值 ListNode<char> *p = ob.chList; ListNode<char> *q = chList = new ListNode<char> ( p→data ); curLen = ob.curLen; while ( p→data != '\0' ) { p = p→link; q = q→link = new ListNode<char> ( p→data ); } return *this; } int string1 :: operator == ( string1& ob ) { //判两串相等