山東大學軟體學院2017-18學年大二資料結構實驗一、二、三、四

Sduzyc發表於2018-10-01

注:實驗程式碼均為自己編寫,均能滿足實驗要求,但實現方法不唯一僅供參考。

實驗一 遞迴練習

1.實驗內容(題目內容,輸入要求,輸出要求)

①、輸入2-10個大於0的正整數,如果輸入0作為結束。

②、輸出這幾個整數的全排列,每個數之間用半形“,”隔開,中間不要有空格,每個排列單獨一行。

③、程式一定要有Input、Output、End提示資訊,但是不要有格式沒有出現的其他提示

④、程式最後增加system(pause),顯示Press any key to continue並暫停。

2.實現原始碼

#include <iostream>

using namespace std;

 

void swap(int &m, int &n) {  //交換兩個元素

    int temp = m;

    m = n;

    n = temp;

}

 

void fullPerm(int Array[], int i, int j) {  //全排列遞迴方法

    if (i == j) {

        for (int k = 0; k <= j; k++) {   //當排到最後輸出一種排列方式

            cout << Array[k];

            if (k<j) {

                cout << ",";

            }

            else

            {

                cout << endl;

            }

        }

    }

    else

    {

        for (int k = i; k <= j; k++)  //以第一個輸入的資料為開頭

        {

            swap(Array[i], Array[k]);   //交換後面兩位相鄰元素

            fullPerm(Array, i + 1, j);   //用遞迴產生多種排列方法

            swap(Array[i], Array[k]);   //交換為首的元素

        }

    }

}

 

int main()

{

    cout << "Input" << endl;

 

    int array[11];

    int n, m;

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

    {

        cin >> n;

        array[i] = n;

        if (n == 0) {

            m = i - 1;          //記錄共輸入了多少個數字

            break;

        }

    }

    cout << "Output" << endl;

    fullPerm(array, 0, m);

    cout << "End" << endl;

    system("pause");

    return 0;

}

實驗二 排序練習

  1. 實驗內容(題目內容,輸入要求,輸出要求)

  1. 輸入2-10個不為零的正整數,遇到0代表輸入結束,0不參與排序。
  2. 數字選擇排序方法,1-氣泡排序、2-插入排序、3-基數排序
  3. 基數排序能夠實現小於10的正整數的排序。
  4. 使用所選排序方法的排序,結果輸出所用方法以及結果,每個數之間用“,”隔開,中間不要有空格。
  5. 輸入輸出請嚴格按下面要求的格式實現

2.資料結構與演算法描述 (整體思路描述,所需要的資料結構與演算法)

①、氣泡排序思路就是交換排序,通過相鄰資料的交換來達到排序的目的。對陣列中各資料依次比較相鄰兩個元素的大小,如果前面資料大於後面,就交換。在用同樣的方法把剩下的資料逐個進行比較,最後便可按從小到大的順序排好。

②、插入排序首先對陣列的前兩個資料進行從小到大排序,再將第三個資料與排好序的兩個資料比較,將第三個資料插入合適位置,然後將第四個資料插入已排好的三個數中,以此類推。

③、基數排序先算最大位數,然後按位依次排序,先排個位再排十位以此類推。

3.實現原始碼

#include <iostream>

using namespace std;

 

template<class T>

void bubblesort(T a[], int n)

{

     //氣泡排序

     for (int i = 1; i < n; i++) {          //共進行n-1步排序

          for (int j = 0; j < n - i; j++) {  //把每次排列的大數排到第n-i的位置上

               if (a[j] > a[j + 1])           //比較相鄰兩個數,大數排後面

                    swap(a[j], a[j + 1]);

          }

     }

     output(a,n);

}

 

template<class T>

void insertsort(T a[], int n)

{

     //插入排序

     for (int i = 1; i < n;i++) {

          T temp = a[i];                        //從第二個數開始先賦值給temp

          int j;

          for (j = i - 1; j >= 0 && temp < a[j];j--) {  //j為選的這個數的前一個數 如果這個數小於前一個數

               a[j + 1] = a[j];                          //那麼這個數賦值為前一個數 不斷向前比較插入

          }

          a[j + 1] = temp;

     }

     output(a,n);

}

 

template <class T>

int maxDigit(T a[], int n)     //為基數排序求出最大位數

{

     int maxdigit = 1;  //求出並儲存一個數中最大的位數是十位還是百位等等

     int divisor = 10;  //除數為10

     for (int i = 0; i < n; i++)   //對每個資料求最大位數

     {

          while (a[i] >= divisor)

          {

               divisor *= 10;

               maxdigit++;

          }

     }

     return maxdigit;

}

 

template<class T>

void radixsort(T a[], int n) {

     //基數排序

     int maxdigit = maxDigit(a, n);

     int *temp = new T[n];

     int *count = new int[10];          //用來計數

     int i, j, k;

     int radix = 1;                     //基數從個位開始

     for (i = 0; i < maxdigit; i++)     //進行輔助函式算出來的最大位數次排序

     {

          for (j = 0; j < 10; j++)

               count[j] = 0;              //每次排序前初始化count陣列

 

          for (j = 0; j < n; j++)

          {

               k = (a[j] / radix) % 10;   //統計每個桶中的數字個數 比如位數是9的有count[9]個

               count[k]++;

          }

 

          for (j = 1; j < 10; j++)

               count[j] = count[j - 1] + count[j]; //將每個桶中的數字分配好在temp中的位置 位置為 count[j] 從1開始

 

          for (j = n - 1; j >= 0; j--)            //將每個桶中數字依次賦值到temp中

          {

               k = (a[j] / radix) % 10;

               temp[count[k] - 1] = a[j];

               count[k]--;

          }

 

          for (j = 0; j < n; j++)                //將臨時陣列複製到傳入的陣列a[]中

               a[j] = temp[j];

          radix = radix * 10;

     }

     output(a, n);

}

 

template<class T>

void output(T a[],int n) {

     //統一格式化輸出結果

     for (int i = 0; i <= n - 1; i++) {

          cout << a[i];

          if (i<n - 1)

          {

               cout << ",";

          }

          else

          {

               cout << endl;

          }

     }

}

 

void threePermutation(int array[],int n) {  //對含有n個資料的陣列array進行排序

     int i;

     cout << "1-氣泡排序,2-插入排序,3-基數排序" << endl;

     cin >> i;   //輸入選項

     cout << "Output" << endl;

     switch (i)

     {

     case 1:

          cout << "氣泡排序" << endl;

          bubblesort(array, n);

          cout << "End" << endl;

          break;

     case 2:

          cout << "插入排序" << endl;

          insertsort(array, n);

          cout << "End" << endl;

          break;

     case 3:

          cout << "基數排序" << endl;

          radixsort(array, n);

          cout << "End" << endl;

          break;

     default:

          break;

     }

}

 

int main() {

     cout << "Input" << endl;

     int array[11];            //建立一個可輸入10個數的陣列

     int n, m;                 //n為當前輸入的資料

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

     {

          cin >> n;

          array[i] = n;

          if (n == 0) {

               m = i;            //m為了記住0前一共輸入了幾個數

               break;

          }

     }

     threePermutation(array, m);

     system("pause");

     return 0;

}

實驗三 線性表操作

1.實驗內容(題目內容,輸入要求,輸出要求)

  1. 建立線性表類。線性表的儲存結構使用連結串列。
  2. 完成表首插入元素、刪除指定元素、搜尋表中是否有指定元素、輸出連結串列。
  3. 輸入n個不為零的整數作為節點元素值,遇到0代表輸入結束(不建立元素值為0的節點),建立連結串列。輸出整個連結串列。
  4. 輸入一個整數,將該數作為一個元素值插入表首位置。輸出整個連結串列。
  5. 輸入一個整數,在連結串列中進行搜尋,輸出其在連結串列中的位置。如果不存在輸出0。
  6. 再一次輸入一個整數,在連結串列中進行搜尋,輸出其在連結串列中的位置。如果不存在輸出0。
  7. 再一次輸入n個不為零的整數作為節點元素值,遇到0代表輸入結束(不建立元素值為0的節點),建立並輸出整個連結串列。
  8. 實現上面兩個連結串列的合併,第一個連結串列在前第二個在後,輸出合併後的連結串列。
  9. 使用連結串列遍歷器輸出合併後的連結串列的反序輸出。

2.實現原始碼

#include<iostream>

using namespace std;

 

class chainNode                //節點類

{

    friend class chain;        //友元類便於訪問private的data與link

    friend class chainIterator;

public:

    chainNode() {};

    chainNode(const int& data);

    chainNode(const int& data, chainNode* link);

private:

    int data;

    chainNode *link;

};

 

chainNode::chainNode(const int& data) {

    this->data = data;

}

chainNode::chainNode(const int& data, chainNode* link) {

    this->data = data;

    this->link = link;

}

 

class chain

{

    friend class chainIterator;          //友元類便於訪問private的firstNode

public:

    chain() { firstNode = 0; };

    ~chain();

    chain &insertAtFirst(const int&x);   //在連結串列表首插入元素x

    chain &deleteNode(const int index);  //刪除指定位置的節點

    int search(const int&x)const;        //查詢連結串列中指定元素x存在返回x不存在返回0

    void push_back(const int&x);         //在連結串列末尾新增元素x

    bool ifexist(const int&x)const;      //查詢連結串列中指定元素x是否存在

private:

    chainNode *firstNode;

};

 

chain::~chain()

{

    while (firstNode != NULL)

    {

        chainNode* nextNode = firstNode->link;

        delete firstNode;

        firstNode = nextNode;

    }

}

 

void chain::push_back(const int&x) {

    chainNode * newNode = new chainNode(x, NULL);

    if (firstNode == NULL) {

        firstNode = newNode;

    }

    else

    {

        chainNode * lastNode = new chainNode(0, firstNode);

        while (lastNode->link)

        {

            lastNode = lastNode->link;

        }

        lastNode->link = newNode;

    }

}

 

chain&chain::insertAtFirst(const int&x) {

    chainNode *element = new chainNode(x, firstNode);

    firstNode = element;

    return*this;

}

 

int chain::search(const int&x)const {

    chainNode *current = firstNode;

    int index = 0;

    while (current)

    {

        index++;

        if (current->data == x)

        {

            return index;

        }

        current = current->link;

    }

    return 0;

}

 

chain&chain::deleteNode(const int index) {

    chainNode*checksize = firstNode;

    int size = 0;

    while (checksize)

    {

        size++;

    }

    delete checksize;

 

    if (index<1 || index>size || size == 0) {

        return*this;

    }

    else

    {

        chainNode*current = firstNode;

        chainNode*before = firstNode;

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

        {

            current = current->link;

        }

        for (int j = 0; j < index - 1; j++)

        {

            before = before->link;

        }

        before->link = current->link;

    }

    return*this;

}

 

bool chain::ifexist(const int&x)const {

    chainNode *ifexist = new chainNode();

    ifexist = firstNode;

    while (ifexist)

    {

        if (ifexist->data == x) {

            return true;

        }

        ifexist = ifexist->link;

    }

    return false;

}

 

class chainIterator   //遍歷器 輸出連結串列

{

private:

    chainNode *current;

public:

    void output(const chain &a) {

        current = a.firstNode;

        while (current)

        {

            cout << current->data;

            if (current->link != NULL)

            {

                cout << ",";

            }

            current = current->link;

        }

        cout << endl;

    }

 

    void addtogether(const chain &a, const chain &b) {

        current = a.firstNode;

        while (current->link)

        {

            current = current->link;

        }

        current->link = b.firstNode;

        current = a.firstNode;

        while (current)

        {

            cout << current->data;

            if (current->link != NULL)

            {

                cout << ",";

            }

            current = current->link;

        }

        cout << endl;

    }

   

    void reverse(const chain &a,chain &b) {

        current = a.firstNode;

        while (current)

        {

            b.insertAtFirst(current->data);

            current = current->link;

        }

        current = b.firstNode;

        while (current)

        {

            cout << current->data;

            if (current->link != NULL)

            {

                cout << ",";

            }

            current = current->link;

        }

        cout << endl;

    }

};

 

int main() {

    chain * chain1 = new chain();

    chain * chain2 = new chain();

    int number = 0;

 

    cout << "Input1" << endl;

    cin >> number;

    chain1->insertAtFirst(number);

     while (1){

        cin >> number;

        if (number == 0) {

            break;

        }

        chain1->push_back(number);

    }

    cout << "Output1" << endl;

    chainIterator c;

    c.output(*chain1);

 

    cout << "Input2" << endl;

    cin >> number;

    chain1->insertAtFirst(number);

    cout << "Output2" << endl;

    c.output(*chain1);

 

    cout << "Input3" << endl;

    cin >> number;

    int a = chain1->search(number);

    cout << "Output3" << endl;

    cout << a << endl;

 

    cout << "Input4" << endl;

    cin >> number;

    a = chain1->search(number);

    cout << "Output4" << endl;

    cout << a << endl;

 

    cout << "Input5" << endl;

    cin >> number;

    chain2->insertAtFirst(number);

    while (1) {

        cin >> number;

        if (number == 0) {

            break;

        }

        chain2->push_back(number);

    }

    cout << "Output5" << endl;

    c.output(*chain2);

    chainIterator c2;

    c2.addtogether(*chain1, *chain2);

    chain * chain3 = new chain();

    c2.reverse(*chain1, *chain3);

 

    cout << "End" << endl;

    system("pause");

}

實驗四 堆疊的應用

1.實驗內容(題目內容,輸入要求,輸出要求)

  1. 1輸入一個數學表示式(假定表示式輸入格式合法),計算表示式結果並輸出。
  2. 數學表示式由單個數字和運算子“+”、“-”、“*”、“/”、“(、) ”構成,例如 2 + 3 * ( 4 + 5 ) - 6 / 4。
  3. 變數、輸出採用整數,只舍不入。

2.實驗原始碼

#include <iostream>

#include <string>

using namespace std;

 

template<class T>

class stack

{

public:

    stack(int initialCapacity);

    bool isEmpty()const;   //判斷堆疊是否空

    bool isFull()const;    //判斷堆疊是否滿

    T top()const;          //返回棧頂元素

    void add(const T& x);  //元素入棧

    T deleteAtTop();       //棧頂元素出棧並且返回此元素

 

private:

    int MaxTop;      //堆疊最大棧頂值

    int Top;         //棧頂

    T *stackArray;   //陣列實現堆疊

};

 

template <class T>

stack<T>::stack(int initialCapacity)

{

    MaxTop = initialCapacity-1;

    Top = -1;

    stackArray = new T[initialCapacity];

}

 

template<class T>

bool stack<T>::isEmpty() const

{

    return Top == -1;

}

 

template<class T>

bool stack<T>::isFull() const

{

    return Top == MaxTop - 1;

}

 

template<class T>

T stack<T>::top() const

{

    if (isEmpty()) throw OutOfBounds();

    else return stackArray[Top];

}

 

 

template<class T>

void stack<T>::add(const T & x)

{

    if (isFull()) throw Nomem();

    stackArray[++Top] = x;

}

 

template<class T>

T stack<T>::deleteAtTop()

{

    if (isEmpty()) throw OutOfBounds();

    else return stackArray[Top--];

}

 

int lengthOfExpression(const char *expression) {         //計算並返回表示式的長度

    int count = 0;

    for (int i = 0; expression[count]!=NULL ; i++)

    {

        count++;

    }

    return count;

}

 

char* changeIntoSuffixExpression(const char *infixExpression) {                 //將輸入的中綴表示式轉換成字尾表示式

    char *suffixExpression = new char[lengthOfExpression(infixExpression)];     //字尾表示式陣列 缺點只能按題意計算單個數字 對於>=10的數字無法計算

    stack<char> * symbolStack = new stack<char>(lengthOfExpression(infixExpression));     //宣告一個符號棧

    int current = 0;                                                                      //在字尾表示式中的位置

    for (int i = 0; i < lengthOfExpression(infixExpression); i++)               //對中綴表示式的每個元素遍歷

    {

        switch (infixExpression[i])

        {

        case '+':

        case '-': {

            if (symbolStack->isEmpty() || symbolStack->top() == '(')     //如果符號棧裡空或者是左括號那麼直接把加減號放入

            {

                symbolStack->add(infixExpression[i]);

            }

            else if (symbolStack->top() == '*' || symbolStack->top() == '/' || symbolStack->top() == '+' || symbolStack->top() == '-')   //如果符號棧裡還有其他符號

            {

                while (!symbolStack->isEmpty())       //只要符號棧不空就把左括號之上的符號全部拿出來 因為這些符號都<= 加減號的優先順序

                {

                    if (symbolStack->top() == '('//遇到左括號就跳出迴圈

                        break;

                    suffixExpression[current++] = symbolStack->deleteAtTop();   //拿出符號放入表示式

                }

                symbolStack->add(infixExpression[i]);  //最後把減號放入符號棧

            }

            break;

        };

 

        case '*':

        case '/': {

            if (symbolStack->isEmpty() || symbolStack->top() == '('||symbolStack->top() == '+' || symbolStack->top() == '-')     //如果符號棧裡空或者是左括號 或者是比乘除優先順序小的加減號那麼直接把加減號放入

            {

                symbolStack->add(infixExpression[i]);

            }

            else if (symbolStack->top() == '*' || symbolStack->top() == '/')   //如果符號棧裡還有與乘除本身相同運算優先順序的符號 即乘除本身

            {

                while (!symbolStack->isEmpty())       //只要符號棧不空就把左括號之上的符號全部拿出來

                {

                    if (symbolStack->top() == '(' || symbolStack->top() == '+' || symbolStack->top() == '-'//如果遇到左括號或者比乘除優先順序小的+-就跳出迴圈直接放入除號

                        break;

                    suffixExpression[current++] = symbolStack->deleteAtTop();   //拿出符號放入表示式

                }

                symbolStack->add(infixExpression[i]);  //最後把除號放入符號棧

            }

            break;

        };

 

        case '(': {

            symbolStack->add(infixExpression[i]); //如果是左括號直接加入符號棧

            break;

        };

 

        case ')': {

            while (!symbolStack->isEmpty())   //如果此時遍歷字首表示式時遇到右括號,並且符號棧不為空就把遇到左括號之前所有符號依次出棧並加入字尾表示式

            {

                if (symbolStack->top() == '(')     //遇到左括號就跳出迴圈

                    break;

                suffixExpression[current++] = symbolStack->deleteAtTop();

            }

            symbolStack->deleteAtTop();             //左括號只出棧不加入字尾表示式

            break;

        };

 

        default: {

            suffixExpression[current++] = infixExpression[i];     //如果是數字直接進入字尾表示式

            break;

 

        };

        }      

    }

    while (!symbolStack->isEmpty())         //遍歷結束後如果符號棧裡還有剩餘符號全部出棧加入字尾表示式

    {

        suffixExpression[current++] = symbolStack->deleteAtTop();  

    }

    suffixExpression[current] = NULL;   //由於為current++當處理完所有位置後最後current必須賦上空值不然會出現指標亂指 每次式子相同但是求出結果不一樣的情況

   

    return suffixExpression;

   

}

 

int result(char *suffixExpression) {             //把字尾表示式從左到右依次取出如果是資料就入棧,是符號就取出棧頂兩個資料計算

    stack<char> * result = new stack<char>(lengthOfExpression(suffixExpression));

    for (int i = 0; i < lengthOfExpression(suffixExpression); i++)

    {

        switch (suffixExpression[i])

        {

        case'+': {

            int a, b; char c;

            a = result->deleteAtTop() - '0';

            b = result->deleteAtTop() - '0';

            c = a + b + '0';

            result->add(c);

            break;

        }

        case'-': {

            int a, b; char c;

            a = result->deleteAtTop() - '0';

            b = result->deleteAtTop() - '0';

            c = b-a+'0';

            result->add(c);

            break;

        }

        case'*': {

            int a, b; char c;

            a = result->deleteAtTop() - '0';

            b = result->deleteAtTop() - '0';

            c = a * b + '0';

            result->add(c);

            break;

        }

        case'/': {

            int a, b; char c;

            a = result->deleteAtTop() - '0';

            b = result->deleteAtTop() - '0';

            c = b/a + '0';

            result->add(c);

            break;

        }

        default:

            result->add(suffixExpression[i]);

            break;

        }

    }

 

    return(result->top() - '0');

}

 

class OutOfBounds :public exception {

public:  OutOfBounds() :exception("ERROR! OutOfBounds\n") {}

};

class Nomem :public exception {

public:  Nomem() :exception("ERROR! Nomem\n") {}

};

 

int main() {

    cout << "Input" << endl;

    string s;

    cin >> s;

    const char*a = s.c_str();

    cout << "Output" << endl;

    char * b = changeIntoSuffixExpression(a);

    int Result = result(b);

    cout << Result << endl;

    cout << "End" << endl;

    system("pause");

}

 

相關文章