[数据结构]厦大2004-2010年本科期末考卷 程序设计题

厦门大学数据结构2004年 程序设计题
------------------------------------------------------------------------
1.(15分)试设计一个结点数据类型为整型的带表头结点的有序单链表,然后设计一个算法,
该算法将这个有序单链表划分为两个单链表,使得第一个单链表中包含原单链表中所有数值为奇数的
结点.第二个单链表中包含原单链表所有数值为偶数的结点.且两个单链表中结点的相对排序顺序
与原单链表中相同.注意:要求使用原链表的空间,表头结点可以另辟空间.
数据结构如下:
typedef struct LinkList{
    ElemType data;
    LinkList *next;
}*L;

void split(LinkList &HL, LinkList &L1, LinkList &L2){
    q1 = L1 = (LinkList)malloc(sizeof(LNode));
    q2 = L2 = (LinkList)malloc(sizeof(LNode));
    p = HL -> next;
    while (p != NULL){
        if (p->data % 2!=0){
            q1 -> next = p;
            q1 = p;
        } else {
            q2 -> next = p;
        }
        p = p -> next;
    }
    q1 -> next = q2 -> next = NULL;
    free(HL);
}


2.(本题20分)试设计一个递归算法,判断二叉树T是否是满二叉树,假设T是以二叉链表存储.
数据结构定义如下:
typedef struct BiTNode{
    TElemType data;
    Struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

满二叉树中任一结点为根的子树都是满二叉树.
算法:
1.如果二叉树T是空树,则是满二叉树
2.如果二叉树T非空,左右子树都是满二叉树,而且深度一样,则T是满二叉树
3.如果二叉树T非空,左子树或右子树不是满二叉树,则不是满二叉树
4.如果二叉树T非空,左右子树都是满二叉树,但深度不一样,则T不是满二叉树

/**
 * 该函数判断二叉树T是否为满二叉树
 * 如果是满二叉树则返回true,depth返回该树的深度
 * 否则返回FALSE,Depth无定义 
 */
Boolean Check(BiTree T,int & Depth){
    int ldepth,rdepth;
    if (T == NULL) {
        Depth = 0;
        return TRUE;
    }
    if (Check(T->lchild.ldepth) == FALSE) return FALSE;
    if (Check(T->rchild.rdepth) == FALSE) return FALSE;
    if (ldepth != rdepth) return FALSE;
    Depth = ldepth + 1;
    return TRUE;
}



3.试设计算法在O(n)时间内将数组A[1..n]划分为左右两个部分,使得左边的所有元素为奇数,
右边的所有元素均为偶数,要求所使用的辅助存储空间大小为O(1).

解:该题的主要思路为:
1.设置两个指针i和j,其中i=,j=n
2.当i<j时,作如下循环
    i不断自增 从左往右 找到第一个偶数
    j不断自减 从右往左 找到第一个奇数
    A[i]与A[j]交换
3.退出循环,算法结束

Adjust(int A[1..n]){
    int i = 1,j = n;
    while (i < j){
        while (A[i]%2 !=0 && i < = n) {
            i++;
        }
        while (i > n || j < 1) break;
        if (i > n || j < 1) break;
        if (i < j){
            A[i] = A[j];
        }
    }
}
算法的时间复杂度为O(n),辅助存储空间为O(1).


B卷
4.试设计一个带头结点的单链表,然后写一个算法将该单链表逆转,要求利用原表
结点空间,不允许申请和使用新的结点空间.

解:
思路1:建立一个单链表,其中的结点从原表得来,即每个原表中得到一个结点,就要将此结点插入到
新链表中.由于要将表逆转,原表的头结点成为新链表的头结点,每次从原表中得到一个结点,
此结点插在头结点之后,作为新链表的第一个结点.

void InverLinkLinkedList(LinkList &L){
    LNode *p,*s;
    p = L -> next;
    L -> next = NULL;
    while(p){
        //p为待逆置链表头指针
        s = p;
        //从p所指链表中删除第一个结点
        p = p -> next;
        s -> next = L -> next;
        //将s结点插入到逆置表的表头
        L -> next = s;
    }
}


方法二:
在遍历原表的时候将各结点的指针逆转,从原表的第一个结点开始,
表头结点的指针在最后修改成指向原表的最后一个结点.
void InvertLinkedList(LinkList &L){
    LNode *p,*s;
    s = L -> next;
    if (s){
        q = NULL;
        p = s;
        while (p){
            p = p -> next;
            s -> next = q;
            q = s;
            s = p;
        }
        L -> next = q;
    }
}


5.(本题20分)设一课二叉树以二叉链表表示,试编写一算法统计二叉树的宽度,即在二叉树的
各层上,求出具有结点数最多的那一层的结点总数.
typedef struct BiTNode{
    TElemType data;
    Struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;

LevelNumber(BiTree T, int NodeNum[], int level){
    //求以*T为根的子树中各层的宽度,存放在NodeNum[],level为*T所在层次号
    if (T != NULL){
        NodeNum[level]++;
        LevelNumber(T -> lchild, NodeNum, h+1);
        LevelNumber(T -> rchild, NodeNum, h+1);
    }
}


int BiTreeWidth(BiTree T){
    for (int i = 0; i < MAXLEVEL: i++){
        NodeNum[i] = 0;
    }
    LevelNumber(T,NodeNum,0);
    wid = NodeNum[0];
    for (i = 0; i < MAXLEVEL;i++){
        if (wid < NodeNum[i]){
            wid = NodeNum[i];
        }
    }
    return wid;
}


解2:->按层序遍历
typedef struct QElem{
    BiTree T;
    int level;
}QElem,*QElemPtr;

int BiTreeWidth(BiTree *T){
    InitQueue(Q);
    q = (QelemPtr)malloc(sizeof(QElem));
    q -> T = T;
    q -> level = 0;
    maxwid = wid = l = 0;
    EnQueue(Q,q);
    while (!QueueEmpty(Q))){
        DeQueue(Q,p);
        if (p -> level == l) wid++;
        else {
            if (wid > maxwid) maxwid = wid;
            l = p -> level;
            wid = 1;
        }

        q = (QelemPtr)malloc(sizeof(QElem));
        q -> T = p -> lchild;
        q -> level = l + 1;
        EnQueue(Q,q);

        q = (QelemPtr)malloc(sizeof(QElem));
        q -> T = p -> rchild;
        q -> level = l + 1;
        EnQueue(Q,q);
        free(p);  
    }
    DestroyQueue(Q);
    Return maxwid;
}

C卷
6.设置T是一棵具有n个结点的二叉树,若给定二叉树T的先序序列和中序序列,并假设T的先序序列
和中序序列分别放在数组PreOrder[1..n]和InOrder[1..n]中,设计一个构造二叉树T的链式存储
结构的算法.以下为结点类型:
typedef struct BiTNode{
    TElemType data;
    Struct BiTNode *lchild,*rchild;
}BiTNode, *BiTree;

解:
void CreateBiTNode(BiTree T,TElemType PreOrder[], int i1,int j1,
                    TElemType InOrder[], int i2, int j2){
    int i = i2;
    if (i1 < j1){
        T = (BiTree)malloc(sizeof(BiNode));
        T -> data = PreOrder[i];
        T -> lchild = NULL;
        T -> rchild = NULL;
        while (InOrder[i] != PreOrder[i1]) i++;
        Create(T -> lchild, PreOrder, i1+1, i-i2+i1,InOrder, i2,i-1);
        Create(T -> rchild, PreOrder, i-i2+i1+1,j1,InOrder,i+1,j2);
    }
    else T = NULL;
}


7.有一种简单的排序算法,叫做计数排序。
这种排序算法对一个待排序的表进行排序,并将排序结果存放到另一个新的表中。
必须注意的是,表中所有待排序的关键字互不相同。
计数排序算法针对表中的每个记录,扫描待排序的表一趟,
统计表中有多少个记录的关键字比该记录的关键字要小。假设针对某一个记录,
统计出的计算值为c,那么这个记录在新的有序表中的合适的存放位置为c+1。
(1)编写实现计数排序的算法
(2)分析该算法的时间复杂性

解:(1)假设数据结构如下:
#define MAXSIZE 20
typedef struct {
    KeyType key;
    InfoType otherinfo;
}RedType;

typedef struct{
   RedType r[MAXSIZE+1];
   int length; 
}

算法如下:
void CountSort(SqList L1,SqList L2){
    //把L1计数排序后,结果放在L2
    int i,j,n,count;
    n = L1.length;
    L2.length = L1.length;
    for (i = 1; i <= n; i++){
        count = 0;
        for (j = 1; j <= n; j++){
            if (L1.r[j] < L1.r[j]) count++;
        }
        L2.r[count+1] = L1.r[i];
    }
}


厦门大学数据结构2005年 程序设计题
---------------------------------------------------------------------
1.在带头结点的非空线性链表中,试设计一算法,将链表中数据域值最小的那个结点移到链表的
最前面,其余各结点的顺序保持不变.要求:不得额外申请新的链结点.

解:程序如下:
typedef struct node{
    int data;
    struct node *next;
}Node, *LinkList;

void MinFirst(LinkList l){
    //空表
    if (L -> next == NULL) return;
    while (p -> next != NULL){
        if (p -> next - > data < ptrmin -> next) ptrmin = p;
        p = p -> next;
    }
    //q指向最小结点,并从链表中删除
    q = ptrmin -> next;
    ptrmin -> next = q -> next;
    q -> next = L -> next;
    //q指向的最小结点插入到链表头
    L -> next = q;
}


2.编写函数判断一棵二叉树是否不含度为1的结点,若任何结点的度都不为1,则返回TRUE,
否则返回FALSE.二叉树采用标准的二叉链表实现.
注意:函数的代码要有注释.

结点与二叉树的数据结构如下:
typedef struct BiTNode{
    TElemType data;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;


bool NoSingleBranchTree(BiTree T){
    if (T == NULL) return true;
    if (T -> lchild == NULL && T -> rchild != NULL) return false;
    if (T -> lchild != NULL && T -> rchild == NULL) return false;
    return NoSingleBranchTree(T->lchild) && NoSingleBranchTreet(T->rchild);
}


3.二路归并排序是从n个长度为1的有序子序列开始的,一种改进方法是先对待排序序列扫描一遍,
并把它划分为若干个长度最大的有序子序列,然后从这些有序子序列开始进行两两归并。
例如,若待排序序列为(15,18,2,26,43,92,89,25,28,30,36,12),
先扫描一遍划分为(15,18),(2,26,43,92),(89),(25,28,30,36),(12)
这5个有序子序列,然后从这5个子序列开始两两归并。
试设计恰当的存储表示方法,并在此基础上实现该算法。

解:设n个待排序元素存放在不带头结点的单链表中,每个结点存放一个元素,头指针为r。
只修改结点中的链指针而不移动结点中的元素值,排序后r仍指向结果链表的第一个结点
void Merge(LinkList La, LinkList Lb, LinkList &Lc){
    if (La && Lb){
        if (La -> data <= Lb -> data){
            Lc = La; pa = La -> next; pb = Lb; 
        } else {
            Lc = Lc; pa = La; pb = Lb -> next;
        }
        pc = Lc;
        
    }
}



(B卷)
4.请利用两个栈S1和S2来模拟一个队列.已知栈的三个运算定义如下:
Push(Stack ST, int x): 元素x入ST栈
Pop(Stack ST,int x): ST栈顶元素出栈,赋给变量x
StackEmpty(Stack ST): 判断ST栈是否为空.
那么如果利用栈的运算来实现该队列的三个运算:
EnQueue: 插入一个元素入队列
DeQueue: 删除一个元素出队列
QueueEmpty: 判队列是否为空

解:利用两个栈S1,S2模拟一个队列(如客户队列)时,当需要向队列中输入元素时,用S1
来存放输入元素,用push运算来实现.当需要从队列中输出元素时,到栈S2中去取,
如果S2为空,则将S1中的元素全部送入S2中,然后再从S2中输出元素.

判断队空的条件是:S1和S2同时为空
程序如下:
Status EnQueue(DataType x){
    if (StackFull(S1)){//S1栈满
        if (StackEmpty(S2)){//S1栈满,S2栈空
            while (!StackEmpty(S1)){
                //将栈S1的内容反向搬到栈S2
                Pop(S1,y);
                Push(S2,y);
            }
            Push(S1,x);
        } else {
            //S1栈满,S2栈非空,则不可进行插入操作
            return ERROR;
        }
    } else {
        //S1栈不满,则直接进栈
        Push(S1,x);
        return OK;
    }
}


Status DeQueue(DataType &x){
    if (!StackEmpty(S2)){
        Pop(S2,x);
        return OK;
    } else {
        if (!StackEmpty(S1)){
            while (!StackEmpty(S1)){
                Pop(S1,y);        
                Push(S2,y);
            }
            Pop(S2,x);
            return OK;
        } else {
            //栈S1和栈S2都空
            return ERROR;
        }
    }
}


5.(15分)用孩子兄弟链表作为树的存储结构,设计算法求出树的深度。
解:一棵树的深度可以递归定义为:
若树为空,则深度为0,否则树的深度为根结点的所有子树深度的最大值+

数据结构为:
typedef struct CSNode {
    ElemType data;
    struct CSNode *firstchild, *nextsibling;
} CSNode,*CSTree;

算法如下:
int depth (CSNode *t){
    CSNode *p;
    int m,d;
    if (T == NULL) return 0;
    p = t -> firstchild;
    m = 0;
    while (p){
        d = depth(p);
        if (d > m) m = d;
        p = p -> nextsibling;
    }
    return m + 1;
}



6.(本题15分)设计一个算法,判断无向图G(图中有n个顶点)是否是一棵树.
解:算法思路:
从第v个顶点出发,对图进行深度优先搜索。
若在算法结束之前,又访问了某一已访问过的顶点,则图G中必定存在环,G不是一棵以v为根的树。
若在算法结束之后,所访问的顶点数小于图的顶点个数n,则图G不是连通图,G也不是一棵以v为根的树。

Boolean visited[MAX]; //用于标识结点是否已被访问
Status (*VisitFunc) (int v); //函数变量

void DFSTraverse(Graph G, status (*VisitFunc)(int v)){
    VisitFunc = Visit;
    for (v = 0; v < G.vexnum; ++v){
        visited[v] = false;
    }
    if (DFS(G,v) == FALSE) return FALSE;
    for (v = 0; v < G.vexnum; ++v){
        if (visited[v] == false) return FALSE;
    }
    return OK;
}

Status DFS(Graph G,int v){
    visited[v] = true;
    visitFunc(v);
    for (w = FirstAdjVex(G,v); w; w = NextAdjVex(G,v,w)){
        if (visited[w]) return FALSE;
        else DFS(G,w);
    }
    return OK;
}



厦门大学数据结构2007年 程序设计题
-----------------------------------------------------------------------
1.试设计一个递归算法(函数),判断二叉树T是否是满二叉树,假设T是以二叉链表存储.
typedef struct BiTNode{
    TElemType data;
    struct BiTNode *lchild,*rchild;
} BiTNode, *BiTree;

算法如下:
(1)如果二叉树T是空树,则为满二叉树
(2)如果二叉树T非空,左右子树不是满二叉树,则不是满二叉树
(3)如果二叉树T非空,左右子树都是满二叉树,单深度不一样,则T不是满二叉树
(4)如果二叉树T非空,左右子树都是满二叉树,且深度一样,则T是满二叉树

Boolean Check(BiTree T, int &Depth){
    //该函数判断二叉树T是否是满二叉树
    //如果是满二叉树,返回TRUE,Depth返回该树的深度;
    //否则返回FALSE,Depth无定义;
    int ldepth,rdepth;
    if (T == NULL){
        Depth = 0;
        return TRUE;
    }
    if (Check(T->lchild,ldepth) == FALSE) return FALSE;
    if (Check(T->rchild,rdepth) == FALSE) return FALSE;
    if (ldepth != rdepth) return FALSE;
    if (ldepth != rdepth) return FALSE;
    Depth = ldepth + 1;
    return TRUE;
}


2.在n个元素中,找出第k大的元素,最好是在O(n)的时间复杂性之内。
请设计数据结构,并在其上设计算法(函数),并给出时间复杂性分析。

static ITEM_select(ITEM[] a, int l, int r, int k){
    while (r > l){
        int i = partition(a,l,r);//partition后,比a[i]小的都在i左边,
        //比a[i]大的都在 i右边。 
        if (i == k) return a[k];
        if (i < k) r = i - 1;//从l到i-1做selection 
        if (i > k) l = i + 1;//从i+1到r做selection 
    }
}



3.给出一系列整数,设计算法求出总和最大的子序列,要求算法的时间复杂度在O(n)之内.

程序如下:
int maxsubsum(int a[n]){
    int maxsum = 0;
    thissum = 0;
    int j = 0;
    for (j = 0; j < n; j++){
        thissum = thissum + a[j];
        if (thissum > maxsum) maxsum = thissum;
        else if (thissum < 0) thissum = 0;
    }
    return maxsum;

}


4.在两个有序线性表中,寻找是否存在共同元素.如果存在共同元素,返回第一个共同元素
在第一个有序表中的位置.请设计数据结构,并在其上设计算法
//参考有序表的归并算法
//数据结构可以使用一维数组,并且第0个元素放空


int SearchCommonItem(int a[n], int b[m]){
    int i = 1; 
    int j = 1;
    while (i <= n && j <= n){
        if (a[i] == b[j]) return i;
        else if (a[i] < b[j]) i++;
        else j++;
    }
    return 0;
}


厦门大学数据结构2008年 程序设计题
-----------------------------------------------------------------------
1.设L是一个带头结点的非递减有序单链表的表头指针,试设计一个算法,将元素e插入到链表L总
合适的地方,使得该链表仍是非递减有序.

数据结构定义如下:
typedef struct Node {
    ElemType e;
    struct Node *next;
} Node, *LinkList;

void Insert(LinkList *L, ElemType e){
    Node *p, *q, *s;
    p = L ->  next;
    q = L;
    while (p != NULL && P -> data <= e){
        q = p;
        p = p -> next;
    }
    s = (Node*)malloc(sizeof(Node));
    s -> data = e;
    s -> next = p;
    q -> next = s;
}


2.给出一系列整数,设计算法求出总和最大的子系列,要求算法的时间复杂性在O(n)之内。

程序如下:
int a[n];//整数序列数组
int maxsubsum(int a[n]){
    int maxsum = 0;
    thissum = 0;
    int j = 0;
    for (j = 0; j < n; j++){
        if (thissum > maxsum) maxsum = thissum;
        else if (thissum < 0) thissum = 0;        
    }
    reurn maxsum;
}
时间复杂度为O(n)


3.在带头结点的非空线性链表中,试设计一算法,
将链表中数据域值最小的那个结点移到链表的最前面,
其余各结点的顺序保持不变。要求:不得额外申请新的链结点。

数据结构如下:
typedef struct Node{
    int data;
    struct node *next;
} Node, *LinkList;

void MinFirst(LinkList L){
    Node *p,*q,*ptrmin;
    if (L -> next == NULL) return; //空表
    ptrmin = L; //指向当前最小结点的前一个结点
    p = L -> next; //p指向当前结点的前一个结点
    while (p -> next != NULL){
        if (p -> next -> data < ptrmin -> next -> data)
            ptrmin = p;
        p = p -> next;
    }
    //q指向最小结点,并从链表中删除
    q = ptrmin -> next;
    ptrmin -> next = q -> next;
    q -> next = L -> next;
    //q指向的最小结点插入到链表头
    L -> next = q;
}



4.请利用两个队列Q1和Q2来模拟一个栈。
已知队列的三个运算定义如下:
bool EnQueue(Queue &Q,int e):插入一个元素e入队列; 
bool DeQueue(Queue &Q,int &e):删除一个元素e出队列;
bool QueueEmpty(Queue Q):判队列为空。
假设数据结构Queue已定义,栈Stack的数据结构定义如下。
typedef struct {
    Queue Q1;
    Queue Q2;
} Stack;

请利用队列的运算来实现该栈的三个运算:
Push(Stack ST,int x):元素x入ST栈;
Pop(Stack ST, int x):ST栈顶元素出栈,赋给变量x;
StackEmpty(Stack  ST):判ST栈是否为空。

程序如下:
思路:队列Q1和Q2中的某一个保存所有的栈元素

bool StackEmpty(Stack S){
    return QueueEmpty(S.Q1) && QueueEmpty(S.Q2);
} 


bool Push(Stack &S, int e){
    if (QueueEmpty(S.Q2) == false)
        return EnQueue(S.Q2, e);
    return EnQueue(S.Q1, e);
}


bool Pop(Stack &S, int &e){
    Queue *from, *to;
    int x;
    if (QueueEmpty(S.Q1) == true && QueueEmpty(S.Q2) == true) return false;
    if (QueueEmpty(S.Q1) == false){
        from = &S.Q1;
        to = &S.Q2;
    } else {
        from = &S.Q2;
        to = &S.Q1;
    }

    DeQueue(*from, x);
    while (QueueEmpty(*from) == false){
        EnQueue(*to, x);
        DeQueue(*from,x);
    }
    e = x;
    return false;
}



5.(本题10分)假设一棵树的存储结构采用双亲表示法,双亲数组为int parent[MaxSize],
其中MaxSize为最大结点个数。树中各结点按先根遍历的次序存放,根结点存于parent[0]。
试编写一个函数,计算下标p所指结点和下标q所指结点的最近公共祖先结点。

int CommonAncestry(int parent[], int MaxSize, int p, int q){
    int i,j;
    for (i = p; i != -1; i = parent[i]){
        for (j = q; j != -1; j = parent[j]){
            if (i == j) return 1;
        }
    }
}


6.(本题10分)12,……,n这n个数,无序地保存在数组c[1..n]中。
请编写一个时间复杂度为O(n)的排序算法,将数组c[1..n]按小到大排序。


void c_sort(int c[], int n){
    int i, x;
    for (i = 1; i <= n; i++){
        while (c[i] != i){
            //前后交换
            x = c[i];
            c[i] = c[x];
            c[x] = x;
        }
    }
}



厦门大学数据结构2009年 程序设计题
-----------------------------------------------------------------------
1.(本题10分)请根据下面的描述写出销售部门的数据结构(用C语言):
假设一个销售部门有n个职员(最多不超过N个,N为100),其中有一个是销售经理。
每个职员都各自有一些客户,客户的个数不固定,不同职员的客户不重叠。

数据结构如下:
#define N 100
typedef struct CustNode{
    Customer cust;
    struct CustNode *next;
} CustNode, *CustLink;

typedef struct {
    Saleman sm;
    CustLink firstcust; //指向第一个销售员
} SalemanNode;

typedef struct SaleDept{
    SalemanNode saleman[N];
    int n; //销售员人数
    int manager; //销售经理在数组saleman[N]中的序号
} SaleDept;


2.(本题10分)一个正整数序列存放在带头结点的链表L中,每个结点存放一个正整数。
请编写算法将该链表调整为所有奇数在链表的前部分,所有偶数在链表的后部分,
并且调整后的奇数序列和偶数序列都与它们在原来序列中的次序一致
(例如:原序列1 2 3 4 5 6,调整后 1 3 5 2 4 6)。
要求:除算法外,还要给出数据结构、算法思想和代码注释。

解:
数据结构定义如下:
typedef struct Node{
    int data;
    struct Node *next;
} *List;

//链表r保存的是倒序的奇数序列,然后逆序插入链表L的头部
void OddEven(List L){
    struct Node *p,*q,*r;
    //r是不带头结点的链表
    p = L; r = null;
    while (p -> next != null){
        if (p -> next -> data %2 == 0){
            //为偶数
            p = p -> next;
        } else {
            q = p -> next; //把结点从链表L中移走
            p -> next = q -> next; //把结点从链表L中移走
            q -> next = r; //加入到链表r中
            r = q;  //加入到链表r中
        }
    }
    //链表r逆序插入到链表r的头部
    while (r != null){
        q = r;
        r = r -> next;
        q -> next = L -> next;
        L -> next = q;
    }
}



厦门大学数据结构2010年 程序设计题
-----------------------------------------------------------------------
1.有一个单链表,其结点的元素值以递增顺序排列,给出数据结构,
并编写一个算法删除该单链表中元素值相同的结点。

//从头到尾扫描单链表,若当前结点与后继结点的值不相同,则指针后移,若相同则删除该后继结点。
typedef struct LNode{
    ElemType data;
    struct LNode *next;
} LNode, *LinkList;
//带头结点

Status Del_Dup(LinkList &L)
{
    p=L->next;  //p指向第一个元素
    if (p ==NULL) return; // 处理空表
    while (p->next!=NULL) {
        if (p->data!=p ->next->data)    //若当前结点与后继结点的值不相同,则指针后移
            p=p->next; 
        else {  //若当前结点与后继结点的值相同,则删除该后继结点
            q=p->next;
            p->next=q->next;
            free(q);
        }
    }
}
/*或者使用两个指针:*/
Status Del_Dup(LinkList &L)
{
    if (L->next ==NULL) return; // 处理空表
    f=L->next; p=f->next; //在扫描过程中,f保持为p的前驱
    while (p) {
        if(f->data!=p ->data){        //若当前结点与后继结点的值不相同,则指针后移
            f=p; 
p=p->next; 
        }
        else{  //若当前结点与后继结点的值相同,则删除该后继结点
            q=p;
            f->next=p->next;
            free(q);
            p=p->next;
        }
    }
}


(B卷)
2.(本题10分)有一个带头结点的单链表L={a1, b1, a2, b2, …, an, bn},
指针变量L指向头结点。请设计一个函数将其拆分成两个带头结点的单链表A和B,
正序链表A={a1, a2, …, an},逆序链表B={bn, bn-1, …, b2, b1}。
要求链表A使用链表L的头结点。
注:函数的头部为void split(LinkList &L, LinkList &A, LinkList &B )。

void split(LinkList &L, LinkList &A, LinkList &B ){ 
    LinkList * p=L->next, *q;
    B = (LinkList ) malloc( sizeof(LinkList) ); //创建B的头结点
    B->next = NULL;
    while( p!=NULL ) {
      q = p->next; assert( q!=NULL);
      p->next = q->next; p = p->next;
      q->next = B->next;  B->next = q->next;
   }
   A =L; L=NULL;
}

void split(LinkList &L, LinkList &A, LinkList &B )
{  LinkList * p=L->next, *q, *rear;
   rear = A = L; L = NULL;
   B = (LinkList ) malloc( sizeof(LinkList) ); //创建B的头结点
   B->next = NULL;
   while( p!=NULL ) {
      q = p->next;  assert( q!=NULL);
      rear->next = p; rear = p; p = q->next;
      q->next = B->next; B->next = q;
   }
   rear->next = NULL; 
}


3.(本题15分)给出一系列整数,请设计算法求出总和最大的子系列,要求算法的时间复杂性在O(n)之内。
答:
int maxsubsum(int  a[n])
{
    int maxsum=0; thissum=0; int j=0;
    for (j=0; j<n;j++)
    {
        thissum=thissum+a[j];
        if (thissum>maxsum)    maxsum=thissum;
        else if (thissum<0)    thissum=0;
    }
    return maxsum;
}
时间复杂性为O(n)。

猜你喜欢

转载自www.cnblogs.com/lx17746071609/p/11793324.html