Tekson

禧之狼

博客园 首页 联系 订阅 管理

 

1. 单链表

1)实现一个单链表

【注】这里不是要求创建一个单链表类,否则会涉及到许多的类成员函数的定义,而这只是一个小编程题而已,不要小题大做。这里仅仅是要求建立一个(特定的)单链表而已。

#include <stdafx.h>

#include <iostream>

using namespace std;

struct Node

{

     int data;

     Node *next;

     Node(const int _data=0, Node *_next=NULL):data(_data), next(_next){}

};

int main()

{

     int a[10] = {1,2,3,4,5,6,7,8,9,10};//笔试中的程序不必用scanfcin进行输入,直接定义一个数组说明问题即可!

     Node *head = new Node(a[0]);

     Node *p = head; //p为遍历链表的指针

     for(int i=1; i!=10; ++i)

     {

         Node *newNode = new Node(a[i]);

         p->next = newNode;

         p = p->next;

     }

     //p->next = NULL; //【注】如果不定义默认构造函数的话则千万不能落掉这一条语句!

     for(p=head; p!=NULL; p=p->next) //既然是链表,就应该用指针或迭代器来对齐遍历

         cout << p->data << " ";

     cout << endl;

}

2)单链表的删除

void deleteNode(Node *&head, const int item) //注意这里是对head的引用,从而可以返回新的链表首地址

{

     Node *currPtr, *prevPtr;

     for(prevPtr=NULL, currPtr=head; currPtr!=NULL && currPtr->data!=item; prevPtr=currPtr, currPtr=currPtr->next);

     if(currPtr == head) //第一种特殊情况:被删除结点为表首结点

     {

         head = head->next;

         delete currPtr;

     }

     else if(NULL == currPtr) //第二种特殊情况,未找到数据等于item的结点

     {

         cerr << "can not find " << item << endl;

         exit(1);

     }

     else //一般情况

     {

         prevPtr->next = currPtr->next;

         delete currPtr;

     }

}

3)单链表的插入

void insertNode(Node *&head, const int item)//注意这里是对head的引用,从而可以返回新的链表首地址

{

     Node *currPtr, *prevPtr; //prevPtrcurrPtr前一个结点的指针

     Node *newNode = new Node(item);

     for(prevPtr=NULL, currPtr=head; currPtr!=NULL && item>=currPtr->data; prevPtr = currPtr, currPtr=currPtr->next);

     //【注】在for循环的终止条件中,currPtr!=NULL必须在currPtr->data<newNode->data前面,否则,当currPtr==NULL时,不会

     //再有currPtr->data,于是运行出错。这是由于&&前后的语句执行的顺行问题造成的,如果前面的条件不符合,后面的条

     //件语句则不再执行。事实上,如果将currPtr->data<newNode->data放在循环内作为if条件的话就不会有这种情况了,不过这

     //样会出现冗余的循环。

     if(NULL == prevPtr) //第一种特殊情况:新结点的值小于原链表头结点的值,新结点应插入表首(等价于NULL == prevPtr

     {

         newNode->next = head;

         head = newNode;

     }

     else if(NULL == currPtr) //第二种特殊情况:节点的值大于原链表最后一个结点的值,新结点应插入表尾

         prevPtr->next = newNode;

         //【注】这里如果改为currPtr = newNode则为错误的,因为prevPtr->next仍然为NULL,而currPtr = newNode仅仅是修改

         //currPtr这个指针的值而已,而prevPtr->next并未改变(因为二者并未通过指针或引用相联系)。

     else//新结点应插入链表中间

     {

         newNode->next = currPtr;

         prevPtr->next = newNode;

     }

}

4)单链表的打印

void printList(const Node *head)

{

     const Node *currPtr; //由于currPtr不是const指针,故不用在声明时初始化。

//这里指针类型必须为const Node *型,否则由于const Node *不能转化为Node *而导致语句currPtr = head编译出错。

     for(currPtr = head; currPtr!=NULL; currPtr=currPtr->next)

         cout << currPtr->data << " ";

     cout << endl;

}

5)单链表的测长

int sizeList(const Node *head)

{

     int n = 0;

     const Node *currPtr; //由于currPtr不是const指针,故不用在声明时初始化。

     for(currPtr=head; currPtr!=NULL; currPtr=currPtr->next)

         ++n;

     return n;

}

6)单链表的排序

选择排序法:

void selectSort(Node *head) //这里参数的类型是不是引用都一样,因为函数体并没有对结点的位置做变化,而改变的仅仅是内容

{

     Node *p1, *p2, *smallPtr;

     for(p1=head; p1->next!=NULL; p1=p1->next)

     {

         smallPtr = p1;

         for(p2=p1->next; p2!=NULL; p2=p2->next)

              if(p2->data < smallPtr->data)

                   smallPtr = p2;

         swap(p1->data, smallPtr->data); //结点本身的位置并不交换,而只交换两个结点之间的数据,从而使问题得到了简化

     }

}

交换排序法:

void exchangeSort(Node *head) //这里参数的类型是不是引用都一样,因为函数体并没有对结点的位置做变化,而改变的仅仅是内容

{

     if(NULL == head)

         return;//防止后面调用直接成员操作符时空结点的未定义错误

     Node *p1, *p2;

     for(p1=head; p1->next!=NULL; p1=p1->next)

     {

         for(p2=p1->next; p2!=NULL; p2=p2->next)

         {

              if(p2->data < p1->data)

                   swap(p1->data, p2->data);

         }

     }

}

冒泡排序法:

void bubbleSort(Node *head)//这里参数的类型是不是引用都一样,因为函数体并没有对结点的位置做变化,而改变的仅仅是内容

{

     Node *p1, *p2; //用于排序

     Node *lastExchangePtr; //冒泡排序法的主线

     //遍历链表,使得p1指向链表的最后一个结点,从而为下面冒泡法的循环做准备

     for(p1=head; p1->next!=NULL; p1=p1->next);

     for(; p1!=head; p1=lastExchangePtr)

     {

         lastExchangePtr = head; //防止内循环没有执行以致lastExchangePtr没有改变从而导致死循环

         for(p2=head; p2!=p1; p2=p2->next)

         {

              if(p2->data > p2->next->data)

              {

                   swap(p2->data, p2->next->data);

                   lastExchangePtr = p2;

              }

         }

     }

}

【注】单链表排序不能用插入排序法进行排序,因为插入排序法涉及到了逆序遍历。外层循环为:for(int i=1; i<n; ++i)而内层循环为:for(int j=i-1; j>0 && a[j]>temp; --j),其中“--j”在单链表中没法表示。虽然冒泡排序法是外后内前,在外层也是逆序,但是其实现为for(i=n-1; i>0; i= lastExchangePos),它通过lastExchangePos的减小达到逆序的目的,从而不必通过指针依次逆序遍历指针,因此可以在单链表中实现。

7)单链表的逆置

方法一(更好):

void reverseList(Node *&head)

{

     if(NULL==head || NULL==head->next) //特殊情况:空链表或只有一个结点

         return;

     Node *prevPtr, *currPtr, *postPtr;//需要三个指针

     for(prevPtr=NULL,currPtr=head,postPtr=head->next; currPtr->next!=NULL;

         prevPtr=currPtr,currPtr=postPtr,postPtr=postPtr->next)//从第一个结点开始进行遍历,最后一个结点未连接

         currPtr->next = prevPtr;

     currPtr->next = prevPtr; //不要丢掉,因为最后一个结点没有和之前的结点像连接

     head = currPtr;

}

方法二:

void reverseList(Node *&head)

{

     if(NULL==head || NULL==head->next)

         return;

     Node *prevPtr, *currPtr, *postPtr;

     prevPtr = head;

     currPtr = head->next; //从第二个结点开始进行遍历,第一个结点未连接

     while(currPtr != NULL)//currPtr == NULL为判别终止条件

     {

         postPtr = currPtr->next; //仅当currPtrNULL时才会有postPtr

         currPtr->next = prevPtr; //每次逆置一次

         prevPtr = currPtr; //指针后移,以便进行下一次循环

         currPtr = postPtr;

     }

     head->next = NULL;

     head = prevPtr;

}

8)求单链表的中点

【要求】链表的结点数未知,怎样遍历一次就得出单链表的中间结点?

Node *searchMiddleNode(Node *head)

{

     if(NULL == head) //而如果为空链表,NULL->next会导致运行错误,故需单独考虑

         return NULL;

     if(NULL == head->next) //而如果为单结点链表,NULL->next->next会导致运行错误,故需单独考虑

         return head;

     Node *p1, *p2;

     for(p1=head, p2=head; p1->next!=NULL && p1->next->next!=NULL; p1=p1->next->next, p2=p2->next);

     //一定要先检查p1->next!=NULL再检查p1->next->next!=NULL,顺序不能颠倒

     return p2;

}

9)合并两个已排序的链表

【要求】合并两个从小到大已排好序的链表,并形成一个新的具有同样顺序的链表

//【合并思想】首先的确定下新的表头结点;其次,currPtr指向最近加入到新链表中的结点,而它所指向的

//min(head1->data, head2->data)所对应的结点(假如是head1),进而currPtr指向该结点(最近加入到

//链表中的结点);而head1指向该结点的下一个结点,以便进行下一次比较。知道head1head2NULL时,

//而未空的那一个子链表直接连到currPtr后即可。

Node *merge(Node *head1, Node *head2)

{   

     Node *head=NULL, *p;//新链表的表头head和遍历指针p

     Node *p1, *p2, *smallPtr;

     //p1p2分别为待合并链表head1head2的遍历指针,smallPtr为指向两个结点中值较小的结点的指针

     for(p1=head1, p2=head2; p1!=NULL && p2!=NULL;)

     {

         if(p1->data < p2->data)

         {

              smallPtr = p1;

              p1 = p1->next;

         }

         else

         {

              smallPtr = p2;

              p2 = p2->next;

         }

         if(NULL == head)

         {

              head = smallPtr;

              p = head;//p指向最近加入到新链表中的结点,即smallPtr

         }

         else

         {

              p->next = smallPtr;

              p = p->next;//p指向最近加入到新链表中的结点,即smallPtr

         }

     }

     //根据上面的循环终止条件,不是head1等于NULL就是head2等于NULL

     if(NULL == p1)

         p->next = p2;

     else

         p->next = p1;

     return head;

}

10)查找两个单链表中相同的元素

int calNumOfSame(int c[], Node *head1, Node *head2)//返回相同元素的个数

{

     Node *p1, *p2;

     int k = 0;

     //先对两链表进行排序,然后再查找相同元素的个数

     selectSort(head1);

     selectSort(head2);

     for(p1=head1, p2=head2; p1!=NULL && p2!=NULL;)

     {

         if(p1->data < p2->data)

              p1 = p1->next;

         else if(p1->data > p2->data)

              p2 = p2->next;

         else

         {

              c[k++] = p1->data;

              p1 = p1->next;

              p2 = p2->next;

         }

     }

     return k;

}

//测试程序:

int main()

{

     int a[] = {10,9,5,8,6,7,4,3,2,1};

     int b[] = {10,8,6,2,4};

     Node *head1, *head2, *p1, *p2;

     head1 = new Node(a[0]);

     p1 = head1;

     head2 = new Node(b[0]);

     p2 = head2;

     for(int i=1; i!=10; ++i)

     {

         Node *newNode = new Node(a[i]);

         p1->next = newNode;

         p1 = p1->next;

     }

     for(int i=1; i!=5; ++i)

     {

         Node *newNode = new Node(b[i]);

         p2->next = newNode;

         p2 = p2->next;

     }

     int c[10];

     int k = calNumOfSame(c, head1, head2);

     for(int i=0; i<k; ++i)

         cout << c[i] << " ";

     cout << endl;

}

posted on 2009-10-08 17:02  珍宝老王  阅读(333)  评论(0编辑  收藏  举报